mirror of
https://github.com/davidhalter/django-stubs.git
synced 2025-12-11 06:21:58 +08:00
Fix CI (#1108)
* Fix CI
* Fix CI
* Fix CI
* Fix CI
* APply black
* APply black
* Fix mypy
* Fix mypy errors in django-stubs
* Fix format
* Fix plugin
* Do not patch builtins by default
* Fix mypy
* Only run mypy on 3.10 for now
* Only run mypy on 3.10 for now
* WHAT THE HELL
* Enable strict mode in mypy
* Enable strict mode in mypy
* Fix tests
* Fix tests
* Debug
* Debug
* Fix tests
* Fix tests
* Add TYPE_CHECKING debug
* Caching maybe?
* Caching maybe?
* Try explicit `${{ matrix.python-version }}`
* Remove debug
* Fix typing
* Finally
This commit is contained in:
78
.github/workflows/release-django-stubs-ext.yml
vendored
78
.github/workflows/release-django-stubs-ext.yml
vendored
@@ -1,78 +0,0 @@
|
||||
# Please, keep it in sync with `release-django-stubs-ext.yml`
|
||||
name: Release django-stubs-ext
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'django-stubs-ext@*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
environment:
|
||||
name: django-stubs-ext-pypi
|
||||
url: https://pypi.org/project/django-stubs-ext
|
||||
|
||||
if: github.repository == 'typeddjango/django-stubs'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U setuptools twine wheel
|
||||
- name: Build package
|
||||
run: |
|
||||
cd ./django_stubs_ext
|
||||
python setup.py --version
|
||||
python setup.py sdist bdist_wheel
|
||||
ls dist
|
||||
|
||||
- name: Publish package to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.DJANGO_STUBS_EXT_PYPI_API_TOKEN }}
|
||||
packages_dir: django_stubs_ext/dist
|
||||
print_hash: true
|
||||
|
||||
- name: Create release
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const tagName = context.ref.replace(/^refs\/tags\//, '');
|
||||
const release = await github.rest.repos.createRelease({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
tag_name: tagName,
|
||||
name: `Release ${tagName}`,
|
||||
generate_release_notes: false,
|
||||
});
|
||||
|
||||
if (release.status < 200 || release.status >= 300) {
|
||||
core.setFailed(`Could not create release for tag '${tagName}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
# https://github.community/t/run-github-actions-job-only-if-previous-job-has-failed/174786/2
|
||||
create-issue-on-failure:
|
||||
name: Create an issue if release failed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
if: ${{ github.repository == 'typeddjango/django-stubs' && always() && needs.build.result == 'failure' }}
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: `Release of django-stubs-ext failure on ${new Date().toDateString()}`,
|
||||
body: `Details: https://github.com/typeddjango/django-stubs/actions/workflows/release-django-stubs-ext.yml`,
|
||||
})
|
||||
76
.github/workflows/release-django-stubs.yml
vendored
76
.github/workflows/release-django-stubs.yml
vendored
@@ -1,76 +0,0 @@
|
||||
# Please, keep it in sync with `release-django-stubs-ext.yml`
|
||||
name: Release django-stubs
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'django-stubs@*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
environment:
|
||||
name: django-stubs-pypi
|
||||
url: https://pypi.org/project/django-stubs
|
||||
|
||||
if: github.repository == 'typeddjango/django-stubs'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install -U pip
|
||||
python -m pip install -U setuptools twine wheel
|
||||
- name: Build package
|
||||
run: |
|
||||
python setup.py --version
|
||||
python setup.py sdist bdist_wheel
|
||||
ls dist
|
||||
|
||||
- name: Publish package to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.DJANGO_STUBS_PYPI_API_TOKEN }}
|
||||
print_hash: true
|
||||
|
||||
- name: Create release
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const tagName = context.ref.replace(/^refs\/tags\//, '');
|
||||
const release = await github.rest.repos.createRelease({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
tag_name: tagName,
|
||||
name: `Release ${tagName}`,
|
||||
generate_release_notes: true,
|
||||
});
|
||||
|
||||
if (release.status < 200 || release.status >= 300) {
|
||||
core.setFailed(`Could not create release for tag '${tagName}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
# https://github.community/t/run-github-actions-job-only-if-previous-job-has-failed/174786/2
|
||||
create-issue-on-failure:
|
||||
name: Create an issue if release failed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
if: ${{ github.repository == 'typeddjango/django-stubs' && always() && needs.build.result == 'failure' }}
|
||||
permissions:
|
||||
issues: write
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: `Release of django-stubs failure on ${new Date().toDateString()}`,
|
||||
body: `Details: https://github.com/typeddjango/django-stubs/actions/workflows/release-django-stubs.yml`,
|
||||
})
|
||||
33
.github/workflows/test.yml
vendored
33
.github/workflows/test.yml
vendored
@@ -27,11 +27,40 @@ jobs:
|
||||
- name: Run pre-commit
|
||||
run: pre-commit install && pre-commit run --all-files
|
||||
|
||||
mypy-self-check:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.7', '3.8', '3.9', '3.10']
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install -U pip setuptools wheel
|
||||
pip install -r ./requirements.txt
|
||||
|
||||
- name: Run mypy on plugin code
|
||||
run: mypy --strict mypy_django_plugin
|
||||
|
||||
- name: Run mypy on ext code
|
||||
run: mypy --strict django_stubs_ext
|
||||
- name: Run mypy on scripts and utils
|
||||
run: mypy --strict scripts
|
||||
# TODO: run this check on versions, not only 3.10
|
||||
- name: Run mypy on stubs
|
||||
if: ${{ matrix.python-version }} == '3.10'
|
||||
run: |
|
||||
mypy --cache-dir=/dev/null --no-incremental django-stubs
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.8']
|
||||
python-version: ['3.9']
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup system dependencies
|
||||
@@ -46,7 +75,7 @@ jobs:
|
||||
pip install -r ./requirements.txt
|
||||
|
||||
- name: Run tests
|
||||
run: pytest --mypy-ini-file=mypy.ini
|
||||
run: PYTHONPATH='.' pytest
|
||||
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -16,17 +16,15 @@ repos:
|
||||
rev: v2.37.3
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py36-plus"]
|
||||
- repo: https://github.com/pre-commit/mirrors-isort
|
||||
rev: v5.10.1
|
||||
args: ["--py37-plus"]
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.10.1
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
args: ["--profile", "black"]
|
||||
- id: isort
|
||||
name: isort (pyi)
|
||||
types: [pyi]
|
||||
args: ["--profile", "black"]
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.6.0
|
||||
hooks:
|
||||
@@ -35,19 +33,3 @@ repos:
|
||||
rev: 3.9.2
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: mypy
|
||||
name: mypy
|
||||
entry: mypy
|
||||
language: system
|
||||
types: [ python ]
|
||||
exclude: "scripts/|django_stubs_ext/"
|
||||
args: [ "--config=mypy.ini", "--cache-dir=/dev/null", "--no-incremental" ]
|
||||
- id: mypy
|
||||
name: mypy (django_stubs_ext)
|
||||
entry: mypy
|
||||
language: system
|
||||
types: [ python ]
|
||||
files: "django_stubs_ext/|django_stubs_ext/tests/"
|
||||
args: [ "--config=mypy.ini", "--cache-dir=/dev/null", "--no-incremental", "--strict" ]
|
||||
|
||||
@@ -116,6 +116,8 @@ This happens because these Django classes do not support [`__class_getitem__`](h
|
||||
|
||||
Note: This monkey patching approach will only work when using Python 3.7 and higher, when the `__class_getitem__` magic method was introduced.
|
||||
|
||||
You can add extra types to patch with `django_stubs_ext.monkeypatch(extra_classes=[YourDesiredType])`
|
||||
|
||||
2. You can use strings instead: `'QuerySet[MyModel]'` and `'Manager[MyModel]'`, this way it will work as a type for `mypy` and as a regular `str` in runtime.
|
||||
|
||||
### How can I create a HttpRequest that's guaranteed to have an authenticated user?
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Mapping, Optional, Sequence, Tuple, Union
|
||||
|
||||
from django import forms
|
||||
@@ -10,11 +9,7 @@ from django.forms.models import ModelForm
|
||||
from django.forms.utils import ErrorDict, ErrorList
|
||||
from django.forms.widgets import Media, Widget
|
||||
from django.utils.safestring import SafeString
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import TypedDict
|
||||
else:
|
||||
from typing import TypedDict
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
ACTION_CHECKBOX_NAME: str
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
@@ -43,11 +42,7 @@ from django.template.response import _TemplateForResponseT
|
||||
from django.urls.resolvers import URLPattern
|
||||
from django.utils.datastructures import _ListOrTuple
|
||||
from django.utils.safestring import SafeString
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal, TypedDict
|
||||
else:
|
||||
from typing import Literal, TypedDict
|
||||
from typing_extensions import Literal, TypedDict
|
||||
|
||||
IS_POPUP_VAR: str
|
||||
TO_FIELD_VAR: str
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import datetime
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Type, Union, overload
|
||||
from uuid import UUID
|
||||
|
||||
@@ -15,11 +14,7 @@ from django.forms.forms import BaseForm
|
||||
from django.forms.formsets import BaseFormSet
|
||||
from django.http.request import HttpRequest
|
||||
from django.utils.datastructures import _IndexableCollection
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class FieldIsAForeignKeyColumnName(Exception): ...
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Type, Union
|
||||
|
||||
from django.contrib.admin.filters import ListFilter
|
||||
@@ -11,11 +10,7 @@ from django.db.models.options import Options
|
||||
from django.db.models.query import QuerySet
|
||||
from django.forms.formsets import BaseFormSet
|
||||
from django.http.request import HttpRequest
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
ALL_VAR: str
|
||||
ORDER_VAR: str
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import sys
|
||||
from typing import Any, List, Optional, Tuple, TypeVar, Union, overload
|
||||
|
||||
from django.db import models
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.expressions import Combinable
|
||||
from django.db.models.fields import BooleanField
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
_T = TypeVar("_T", bound=Model)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Iterable, Optional, Set, Tuple, Type, TypeVar, Union
|
||||
|
||||
from django.contrib.auth.base_user import AbstractBaseUser as AbstractBaseUser
|
||||
@@ -8,11 +7,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.manager import EmptyManager
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
_AnyUser = Union[Model, "AnonymousUser"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.core import validators
|
||||
from django.core.validators import RegexValidator
|
||||
|
||||
class ASCIIUsernameValidator(validators.RegexValidator): ...
|
||||
class UnicodeUsernameValidator(validators.RegexValidator): ...
|
||||
class ASCIIUsernameValidator(RegexValidator): ...
|
||||
class UnicodeUsernameValidator(RegexValidator): ...
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any, Dict, List, Tuple, Type
|
||||
|
||||
from django.apps.config import AppConfig
|
||||
from django.apps.registry import Apps
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
from django.contrib import admin as admin
|
||||
from django.contrib import admin
|
||||
|
||||
class FlatPageAdmin(admin.ModelAdmin):
|
||||
form: Any = ...
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Any
|
||||
|
||||
from django.contrib.gis.db import models as models
|
||||
from django.contrib.gis.db.backends.base.models import SpatialRefSysMixin as SpatialRefSysMixin
|
||||
from django.contrib.gis.db import models
|
||||
from django.contrib.gis.db.backends.base.models import SpatialRefSysMixin
|
||||
|
||||
class OracleGeometryColumns(models.Model):
|
||||
table_name: Any = ...
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import sys
|
||||
from typing import Any, Union
|
||||
|
||||
from django.contrib.gis.db.backends.base.operations import BaseSpatialOperations
|
||||
from django.contrib.gis.db.backends.utils import SpatialOperator
|
||||
from django.db.backends.postgresql.operations import DatabaseOperations
|
||||
from django.db.models import Func
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
BILATERAL: Literal["bilateral"]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any, Optional
|
||||
|
||||
from django import forms as forms
|
||||
from django import forms
|
||||
|
||||
class GeometryField(forms.Field):
|
||||
widget: Any = ...
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Optional, Type
|
||||
|
||||
from django.db import models
|
||||
from django.db.models.lookups import PostgresOperatorLookup
|
||||
from psycopg2.extras import DateRange, DateTimeTZRange, NumericRange, Range
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class RangeBoundary(models.Expression):
|
||||
lower: str
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from typing import Dict, Literal, Tuple
|
||||
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.migrations import AddConstraint, AddIndex, RemoveIndex
|
||||
from django.db.migrations.operations.base import Operation
|
||||
from typing_extensions import Literal
|
||||
|
||||
class CreateExtension(Operation):
|
||||
reversible: bool = ...
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
from django.contrib import admin as admin
|
||||
from django.contrib import admin
|
||||
|
||||
class RedirectAdmin(admin.ModelAdmin):
|
||||
list_display: Any = ...
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
from django.contrib import admin as admin
|
||||
from django.contrib import admin
|
||||
|
||||
class SiteAdmin(admin.ModelAdmin):
|
||||
list_display: Any = ...
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Optional, Sequence, Tuple, Type, overload
|
||||
|
||||
from django.core.checks.messages import CheckMessage
|
||||
from django.core.files.storage import FileSystemStorage, Storage
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
searched_locations: Any
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import sys
|
||||
from typing import Any, Callable, List, Optional, Sequence, Set, TypeVar, Union
|
||||
|
||||
from django.apps.config import AppConfig
|
||||
from django.core.checks.messages import CheckMessage
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class Tags:
|
||||
admin: str = ...
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class FieldDoesNotExist(Exception): ...
|
||||
class AppRegistryNotReady(Exception): ...
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from argparse import ArgumentParser, HelpFormatter, Namespace
|
||||
from io import TextIOBase
|
||||
from typing import Any, Callable, Iterable, List, Optional, Sequence, Set, TextIO, Tuple, Union
|
||||
@@ -6,11 +5,7 @@ from typing import Any, Callable, Iterable, List, Optional, Sequence, Set, TextI
|
||||
from django.apps.config import AppConfig
|
||||
from django.core.management.color import Style
|
||||
from django.utils.datastructures import _ListOrTuple
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class CommandError(Exception):
|
||||
def __init__(self, *args: Any, returncode: int = ..., **kwargs: Any) -> None: ...
|
||||
|
||||
@@ -2,7 +2,7 @@ from typing import Any
|
||||
|
||||
from django.utils.connection import ConnectionProxy
|
||||
|
||||
from . import migrations
|
||||
from . import migrations as migrations
|
||||
from .backends.base.base import BaseDatabaseWrapper
|
||||
from .utils import DEFAULT_DB_ALIAS as DEFAULT_DB_ALIAS # Not exported in __all__
|
||||
from .utils import DJANGO_VERSION_PICKLE_KEY as DJANGO_VERSION_PICKLE_KEY
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sys
|
||||
from typing import Any, Dict, List, Sequence
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class _QuoteCallable(Protocol):
|
||||
"""Get rid of `cannot assign to method`"""
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Optional, Type
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper as BaseDatabaseWrapper
|
||||
from typing_extensions import Literal
|
||||
|
||||
from .client import DatabaseClient
|
||||
from .creation import DatabaseCreation
|
||||
@@ -10,11 +10,6 @@ from .introspection import DatabaseIntrospection
|
||||
from .operations import DatabaseOperations
|
||||
from .validation import DatabaseValidation
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
version: Any
|
||||
django_conversions: Any
|
||||
server_version_re: Any
|
||||
|
||||
@@ -9,7 +9,8 @@ class SQLCompiler(compiler.SQLCompiler):
|
||||
class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler): ...
|
||||
|
||||
class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler):
|
||||
def as_sql(self) -> _AsSqlType: ...
|
||||
# https://github.com/django/django/blob/242499f2dc2bf24a9a5c855690a2e13d3303581a/django/db/backends/mysql/compiler.py#L26
|
||||
def as_sql(self) -> _AsSqlType: ... # type: ignore[override]
|
||||
|
||||
class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler): ...
|
||||
class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler): ...
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import datetime
|
||||
import sys
|
||||
import types
|
||||
from contextlib import contextmanager
|
||||
from decimal import Decimal
|
||||
@@ -21,10 +20,7 @@ from typing import (
|
||||
)
|
||||
from uuid import UUID
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
logger: Logger
|
||||
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import sys
|
||||
from typing import List, Optional, Sequence, Set, Tuple, Union
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||
from django.db.migrations.migration import Migration
|
||||
from typing_extensions import Protocol
|
||||
|
||||
from .loader import MigrationLoader
|
||||
from .recorder import MigrationRecorder
|
||||
from .state import ProjectState
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
|
||||
class _ProgressCallbackT(Protocol):
|
||||
def __call__(self, __action: str, __migration: Optional[Migration] = ..., __fake: Optional[bool] = ...) -> None: ...
|
||||
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Mapping, Optional, Sequence, Tuple, Union
|
||||
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
from django.utils.datastructures import _ListOrTuple
|
||||
from typing_extensions import Literal, Protocol
|
||||
|
||||
from .base import Operation
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal, Protocol
|
||||
else:
|
||||
from typing import Literal, Protocol
|
||||
|
||||
class SeparateDatabaseAndState(Operation):
|
||||
database_operations: Sequence[Operation] = ...
|
||||
state_operations: Sequence[Operation] = ...
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from typing import Iterator, Optional, Tuple, Union
|
||||
|
||||
from django.db.migrations.state import ModelState, ProjectState
|
||||
from django.db.models import Field
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
def resolve_relation(model, app_label: Optional[str] = ..., model_name: Optional[str] = ...) -> Tuple[str, str]: ...
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import datetime
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union
|
||||
|
||||
@@ -10,11 +9,7 @@ from django.db.models.lookups import Lookup, Transform
|
||||
from django.db.models.query import QuerySet
|
||||
from django.db.models.sql.compiler import SQLCompiler, _AsSqlType
|
||||
from django.db.models.sql.query import Query
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class SQLiteNumericMixin:
|
||||
def as_sqlite(self, compiler: SQLCompiler, connection: BaseDatabaseWrapper, **extra_context: Any) -> _AsSqlType: ...
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import decimal
|
||||
import sys
|
||||
import uuid
|
||||
from datetime import date
|
||||
from datetime import datetime as real_datetime
|
||||
@@ -32,11 +31,7 @@ from django.forms import Field as FormField
|
||||
from django.forms import Widget
|
||||
from django.utils.datastructures import DictWrapper
|
||||
from django.utils.functional import _Getter
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class Empty: ...
|
||||
class NOT_PROVIDED: ...
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Iterable, Optional, Type, TypeVar, Union, overload
|
||||
|
||||
from django.core import validators # due to weird mypy.stubtest error
|
||||
@@ -10,11 +8,7 @@ from django.db.models.base import Model
|
||||
from django.db.models.fields import Field, _ErrorMessagesT, _FieldChoices
|
||||
from django.db.models.query_utils import DeferredAttribute
|
||||
from django.utils._os import _PathCompatible
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
class FieldFile(File):
|
||||
instance: Model = ...
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Type, TypeVar, Union, overload
|
||||
from uuid import UUID
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from django.core import validators # due to weird mypy.stubtest error
|
||||
from django.db import models
|
||||
from django.db.models.base import Model
|
||||
@@ -26,6 +20,7 @@ from django.db.models.fields.reverse_related import ManyToOneRel as ManyToOneRel
|
||||
from django.db.models.fields.reverse_related import OneToOneRel as OneToOneRel
|
||||
from django.db.models.manager import RelatedManager
|
||||
from django.db.models.query_utils import FilteredRelation, PathInfo, Q
|
||||
from typing_extensions import Literal
|
||||
|
||||
_T = TypeVar("_T", bound=models.Model)
|
||||
_F = TypeVar("_F", bound=models.Field)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Type, Union
|
||||
from typing import Any, Callable, List, Optional, Sequence, Tuple, Type, Union
|
||||
|
||||
from django.db.models import Q
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.fields import AutoField, Field, _AllLimitChoicesTo, _ChoicesList, _LimitChoicesTo
|
||||
from django.db.models.fields.related import ForeignKey, ForeignObject, ManyToManyField, OneToOneField
|
||||
from django.db.models.lookups import BuiltinLookup, Lookup, StartsWith
|
||||
from django.db.models.lookups import Lookup, StartsWith
|
||||
from django.db.models.query_utils import FilteredRelation, PathInfo
|
||||
from django.db.models.sql.where import WhereNode
|
||||
from typing_extensions import Literal
|
||||
|
||||
from .mixins import FieldCacheMixin
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
# Common note: `model` and `through` can be of type `str` when passed to `__init__`.
|
||||
# When parent's `contribute_to_class` is called (during startup),
|
||||
# strings are resolved to real model classes.
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import sys
|
||||
from typing import Any, Generic, Iterable, List, Mapping, Optional, Tuple, Type, TypeVar, Union
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||
from django.db.models.expressions import Expression, Func
|
||||
from django.db.models.query_utils import RegisterLookupMixin
|
||||
from django.db.models.sql.compiler import SQLCompiler, _AsSqlType, _ParamT
|
||||
from django.utils.datastructures import OrderedSet
|
||||
from typing_extensions import Literal
|
||||
|
||||
_L = TypeVar("_L", bound="Lookup")
|
||||
_T = TypeVar("_T")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Generic, Iterable, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union, overload
|
||||
|
||||
from django.apps.config import AppConfig
|
||||
@@ -13,11 +12,7 @@ from django.db.models.fields.reverse_related import ForeignObjectRel
|
||||
from django.db.models.manager import Manager
|
||||
from django.db.models.query_utils import PathInfo
|
||||
from django.utils.datastructures import ImmutableList, _ListOrTuple
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
PROXY_PARENTS: object
|
||||
EMPTY_RELATION_TREE: Any
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from typing import (
|
||||
Any,
|
||||
@@ -17,23 +16,17 @@ from typing import (
|
||||
Union,
|
||||
)
|
||||
|
||||
from django.db.models.sql.compiler import _AsSqlType
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.expressions import BaseExpression
|
||||
from django.db.models.fields import Field
|
||||
from django.db.models.fields.mixins import FieldCacheMixin
|
||||
from django.db.models.lookups import Lookup, Transform
|
||||
from django.db.models.sql.compiler import SQLCompiler
|
||||
from django.db.models.sql.compiler import SQLCompiler, _AsSqlType
|
||||
from django.db.models.sql.query import Query
|
||||
from django.db.models.sql.where import WhereNode
|
||||
from django.utils import tree
|
||||
from typing_extensions import Literal
|
||||
|
||||
PathInfo = namedtuple(
|
||||
"PathInfo", ["from_opts", "to_opts", "target_fields", "join_field", "m2m", "direct", "filtered_relation"]
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
import sys
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from itertools import chain
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union, overload
|
||||
from uuid import UUID
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||
from django.db.backends.utils import CursorWrapper
|
||||
from django.db.models.base import Model
|
||||
from django.db.models.expressions import BaseExpression, Expression
|
||||
from django.db.models.sql.query import Query
|
||||
from django.db.models.sql.subqueries import AggregateQuery, DeleteQuery, InsertQuery, UpdateQuery
|
||||
from typing_extensions import Literal
|
||||
|
||||
_ParamT = Union[str, int]
|
||||
_ParamsT = List[_ParamT]
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import sys
|
||||
from typing import Dict, Final, Pattern, Tuple
|
||||
from typing import Dict, Pattern, Tuple
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Final, Literal
|
||||
|
||||
GET_ITERATOR_CHUNK_SIZE: Final[int] = ...
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import collections
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from typing import Any, Callable, Dict, FrozenSet, Iterable, Iterator, List, Optional, Sequence, Set, Tuple, Type, Union
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
from django.db.backends.base.base import BaseDatabaseWrapper
|
||||
from django.db.backends.utils import CursorWrapper
|
||||
from django.db.models import Field, FilteredRelation, Model, Q, QuerySet
|
||||
@@ -18,6 +12,7 @@ from django.db.models.query_utils import PathInfo, RegisterLookupMixin
|
||||
from django.db.models.sql.compiler import SQLCompiler
|
||||
from django.db.models.sql.datastructures import BaseTable, Join
|
||||
from django.db.models.sql.where import WhereNode
|
||||
from typing_extensions import Literal
|
||||
|
||||
JoinInfo = namedtuple("JoinInfo", ("final_field", "targets", "opts", "joins", "path", "transform_function"))
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
@@ -34,11 +33,7 @@ from django.forms.renderers import BaseRenderer
|
||||
from django.forms.utils import ErrorList, _DataT, _FilesT
|
||||
from django.forms.widgets import ChoiceWidget, Input, Widget
|
||||
from django.utils.datastructures import _IndexableCollection, _ListOrTuple, _PropertyDescriptor
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
ALL_FIELDS: Literal["__all__"]
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import datetime
|
||||
import sys
|
||||
from typing import Any, Dict, Iterable, Iterator, List, Mapping, Optional, Sequence, Tuple, Type, Union
|
||||
|
||||
from django.core.files.base import File
|
||||
@@ -9,12 +8,7 @@ from django.forms.utils import _DataT, _FilesT
|
||||
from django.utils.datastructures import _ListOrTuple
|
||||
from django.utils.functional import _Getter
|
||||
from django.utils.safestring import SafeString
|
||||
from typing_extensions import Literal
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Literal, Protocol
|
||||
|
||||
_OptAttrs = Dict[str, Any]
|
||||
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import sys
|
||||
from typing import IO, Any, Dict, Iterator, List, Mapping, Optional, Tuple, Union
|
||||
|
||||
from django.http.request import QueryDict
|
||||
from django.utils.datastructures import ImmutableList, MultiValueDict
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
class MultiPartParserError(Exception): ...
|
||||
class InputStreamExhausted(Exception): ...
|
||||
|
||||
RAW: Literal["raw"] = "raw"
|
||||
FILE: Literal["file"] = "file"
|
||||
FIELD: Literal["field"] = "field"
|
||||
RAW: Literal["raw"]
|
||||
FILE: Literal["file"]
|
||||
FIELD: Literal["field"]
|
||||
|
||||
class MultiPartParser:
|
||||
def __init__(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from io import BytesIO
|
||||
from typing import (
|
||||
Any,
|
||||
@@ -25,11 +24,7 @@ from django.contrib.sites.models import Site
|
||||
from django.core.files import uploadedfile, uploadhandler
|
||||
from django.urls import ResolverMatch
|
||||
from django.utils.datastructures import CaseInsensitiveMapping, ImmutableList, MultiValueDict
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
RAISE_ERROR: object = ...
|
||||
host_validation_re: Pattern[str] = ...
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Callable, List, Mapping, Optional, Protocol, Sequence, Type, TypeVar, Union, overload
|
||||
|
||||
from django.db.models import Manager, QuerySet
|
||||
@@ -7,11 +6,7 @@ from django.http import HttpRequest
|
||||
from django.http.response import HttpResponse as HttpResponse
|
||||
from django.http.response import HttpResponsePermanentRedirect as HttpResponsePermanentRedirect
|
||||
from django.http.response import HttpResponseRedirect as HttpResponseRedirect
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
def render(
|
||||
request: HttpRequest,
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import sys
|
||||
from typing import Any, Callable, Dict, Optional, Sequence, Union
|
||||
|
||||
from django.urls.resolvers import ResolverMatch
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
def resolve(path: str, urlconf: Optional[str] = ...) -> ResolverMatch: ...
|
||||
def reverse(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import (
|
||||
Any,
|
||||
Collection,
|
||||
@@ -16,10 +15,7 @@ from typing import (
|
||||
overload,
|
||||
)
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
_K = TypeVar("_K")
|
||||
_V = TypeVar("_V")
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import sys
|
||||
from datetime import date
|
||||
from datetime import datetime as builtin_datetime
|
||||
from datetime import time as builtin_time
|
||||
from typing import Any, Optional, Pattern, Union
|
||||
|
||||
from django.utils.timezone import _TzInfoT
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
re_formatchars: Pattern[str]
|
||||
re_escaped: Pattern[str]
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import datetime
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from typing import Any, TypeVar, Union, overload
|
||||
|
||||
if sys.version_info < (3, 10):
|
||||
from typing_extensions import TypeGuard
|
||||
else:
|
||||
from typing import TypeGuard
|
||||
|
||||
from django.utils.functional import Promise
|
||||
from typing_extensions import Literal
|
||||
from typing_extensions import Literal, TypeGuard
|
||||
|
||||
class DjangoUnicodeDecodeError(UnicodeDecodeError):
|
||||
obj: bytes = ...
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import sys
|
||||
from functools import wraps as wraps # noqa: F401
|
||||
from typing import Any, Callable, Generic, List, Optional, Tuple, Type, TypeVar, Union, overload
|
||||
|
||||
from django.db.models.base import Model
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
import types
|
||||
from contextlib import ContextDecorator
|
||||
from datetime import date
|
||||
@@ -9,18 +8,9 @@ from datetime import timezone
|
||||
from datetime import tzinfo as tzinfo
|
||||
from typing import Any, Optional, Type, Union, overload
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
|
||||
if sys.version_info < (3, 10):
|
||||
from typing_extensions import TypeGuard
|
||||
else:
|
||||
from typing import TypeGuard
|
||||
|
||||
import pytz
|
||||
from pytz import BaseTzInfo
|
||||
from typing_extensions import Literal, TypeGuard
|
||||
|
||||
_PytzTzInfoT = Union[pytz.tzinfo.BaseTzInfo, pytz._FixedOffset]
|
||||
_TzInfoT = Union[_PytzTzInfoT, tzinfo]
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import gettext as gettext_module
|
||||
import sys
|
||||
from gettext import NullTranslations
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Pattern, Protocol, Tuple, TypeVar, Union
|
||||
from typing import Any, Dict, Iterator, List, Optional, Pattern, Protocol, Tuple, TypeVar, Union
|
||||
|
||||
from django.http.request import HttpRequest
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
CONTEXT_SEPARATOR: Literal["\x04"]
|
||||
accept_language_re: Pattern[str]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import sys
|
||||
from typing import Any, Dict, Generic, Optional, Type, TypeVar, Union
|
||||
|
||||
from django.db import models
|
||||
@@ -8,11 +7,7 @@ from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.datastructures import _ListOrTuple
|
||||
from django.views.generic.base import ContextMixin, TemplateResponseMixin, View
|
||||
from django.views.generic.detail import BaseDetailView, SingleObjectMixin, SingleObjectTemplateResponseMixin
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Literal
|
||||
else:
|
||||
from typing import Literal
|
||||
from typing_extensions import Literal
|
||||
|
||||
_FormT = TypeVar("_FormT", bound=BaseForm)
|
||||
_ModelFormT = TypeVar("_ModelFormT", bound=BaseModelForm)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import builtins
|
||||
from typing import Any, Generic, Iterable, List, Optional, Tuple, Type, TypeVar
|
||||
|
||||
from django import VERSION as VERSION
|
||||
@@ -17,6 +18,8 @@ from django.views.generic.detail import SingleObjectMixin
|
||||
from django.views.generic.edit import DeletionMixin, FormMixin
|
||||
from django.views.generic.list import MultipleObjectMixin
|
||||
|
||||
__all__ = ["monkeypatch"]
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_VersionSpec = Tuple[int, int]
|
||||
|
||||
@@ -67,7 +70,7 @@ _need_generic: List[MPGeneric[Any]] = [
|
||||
]
|
||||
|
||||
|
||||
def monkeypatch(extra_classes: Optional[Iterable[type]] = None) -> None:
|
||||
def monkeypatch(extra_classes: Optional[Iterable[type]] = None, include_builtins: bool = True) -> None:
|
||||
"""Monkey patch django as necessary to work properly with mypy."""
|
||||
|
||||
# Add the __class_getitem__ dunder.
|
||||
@@ -81,5 +84,7 @@ def monkeypatch(extra_classes: Optional[Iterable[type]] = None) -> None:
|
||||
for cls in extra_classes:
|
||||
cls.__class_getitem__ = classmethod(lambda cls, *args, **kwargs: cls) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
__all__ = ["monkeypatch"]
|
||||
# Add `reveal_type` and `reveal_locals` helpers if needed:
|
||||
if include_builtins:
|
||||
builtins.reveal_type = lambda _: None
|
||||
builtins.reveal_locals = lambda: None
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
if sys.version_info < (3, 8):
|
||||
from typing_extensions import Protocol
|
||||
else:
|
||||
from typing import Protocol
|
||||
from typing_extensions import Protocol
|
||||
|
||||
|
||||
# Used internally by mypy_django_plugin.
|
||||
class AnyAttrAllowed(Protocol):
|
||||
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
|
||||
setup(
|
||||
name="django-stubs-ext",
|
||||
version="0.5.0",
|
||||
version="0.6.0",
|
||||
description="Monkey-patching and extensions for django-stubs",
|
||||
long_description=readme,
|
||||
long_description_content_type="text/markdown",
|
||||
@@ -23,7 +23,7 @@ setup(
|
||||
maintainer="Nikita Sobolev",
|
||||
maintainer_email="mail@sobolevn.me",
|
||||
py_modules=[],
|
||||
python_requires=">=3.6",
|
||||
python_requires=">=3.7",
|
||||
install_requires=dependencies,
|
||||
packages=["django_stubs_ext", *find_packages(exclude=["scripts"])],
|
||||
package_data={"django_stubs_ext": ["py.typed"]},
|
||||
@@ -33,6 +33,7 @@ setup(
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Typing :: Typed",
|
||||
"Framework :: Django",
|
||||
"Framework :: Django :: 2.2",
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import builtins
|
||||
from contextlib import suppress
|
||||
from typing import Iterable, Optional
|
||||
from typing import Iterable, List, Optional
|
||||
|
||||
import pytest
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from django.db.models import Model
|
||||
from django.forms.models import ModelForm
|
||||
from django.views import View
|
||||
from typing_extensions import Protocol
|
||||
|
||||
import django_stubs_ext
|
||||
@@ -19,7 +18,10 @@ class _MakeGenericClasses(Protocol):
|
||||
"""Used to represent a type of ``make_generic_classes`` fixture."""
|
||||
|
||||
def __call__(
|
||||
self, django_version: Optional[_VersionSpec] = None, extra_classes: Optional[Iterable[type]] = None
|
||||
self,
|
||||
django_version: Optional[_VersionSpec] = None,
|
||||
extra_classes: Optional[Iterable[type]] = None,
|
||||
include_builtins: bool = True,
|
||||
) -> None:
|
||||
...
|
||||
|
||||
@@ -29,7 +31,7 @@ def make_generic_classes(
|
||||
request: FixtureRequest,
|
||||
monkeypatch: MonkeyPatch,
|
||||
) -> _MakeGenericClasses:
|
||||
_extra_classes: list[type] = []
|
||||
_extra_classes: List[type] = []
|
||||
|
||||
def fin() -> None:
|
||||
for el in _need_generic:
|
||||
@@ -38,13 +40,22 @@ def make_generic_classes(
|
||||
for cls in _extra_classes:
|
||||
with suppress(AttributeError):
|
||||
delattr(cls, "__class_getitem__")
|
||||
_extra_classes.clear()
|
||||
with suppress(AttributeError):
|
||||
del builtins.reveal_type
|
||||
with suppress(AttributeError):
|
||||
del builtins.reveal_locals
|
||||
|
||||
def factory(django_version: Optional[_VersionSpec] = None, extra_classes: Optional[Iterable[type]] = None) -> None:
|
||||
def factory(
|
||||
django_version: Optional[_VersionSpec] = None,
|
||||
extra_classes: Optional[Iterable[type]] = None,
|
||||
include_builtins: bool = True,
|
||||
) -> None:
|
||||
if extra_classes:
|
||||
_extra_classes.extend(extra_classes)
|
||||
if django_version is not None:
|
||||
monkeypatch.setattr(patch, "VERSION", django_version)
|
||||
django_stubs_ext.monkeypatch(extra_classes)
|
||||
django_stubs_ext.monkeypatch(extra_classes=extra_classes, include_builtins=include_builtins)
|
||||
|
||||
request.addfinalizer(fin)
|
||||
return factory
|
||||
@@ -64,14 +75,17 @@ def test_patched_generics(make_generic_classes: _MakeGenericClasses) -> None:
|
||||
|
||||
def test_patched_extra_classes_generics(make_generic_classes: _MakeGenericClasses) -> None:
|
||||
"""Test that the generics actually get patched for extra classes."""
|
||||
extra_classes = [View]
|
||||
|
||||
class _NotGeneric:
|
||||
pass
|
||||
|
||||
extra_classes = [_NotGeneric]
|
||||
make_generic_classes(django_version=None, extra_classes=extra_classes)
|
||||
|
||||
for cls in extra_classes:
|
||||
assert cls[type] is cls # type: ignore[misc]
|
||||
|
||||
class TestView(View[Model]): # type: ignore[type-arg]
|
||||
class _TestGeneric(_NotGeneric[Model]): # type: ignore
|
||||
pass
|
||||
|
||||
|
||||
@@ -106,7 +120,17 @@ def test_mypy_builtins_not_patched_globally(
|
||||
This should only happend during `django.setup()`
|
||||
(https://github.com/typeddjango/django-stubs/issues/609).
|
||||
"""
|
||||
make_generic_classes()
|
||||
make_generic_classes(include_builtins=False)
|
||||
|
||||
assert not hasattr(builtins, "reveal_type")
|
||||
assert not hasattr(builtins, "reveal_locals")
|
||||
|
||||
|
||||
def test_mypy_builtins_patched(
|
||||
make_generic_classes: _MakeGenericClasses,
|
||||
) -> None:
|
||||
"""Ensures that builtins are patched by default."""
|
||||
make_generic_classes()
|
||||
|
||||
assert hasattr(builtins, "reveal_type")
|
||||
assert hasattr(builtins, "reveal_locals")
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# `main` is empty on purpose, because we test the `django.setup()` step.
|
||||
# It executes the `myapp/models.py` file and should not produce anything,
|
||||
# because `reveal_type` and `reveal_locals` are patched.
|
||||
monkeypatch: true
|
||||
installed_apps:
|
||||
- myapp
|
||||
files:
|
||||
|
||||
5
mypy.ini
5
mypy.ini
@@ -1,10 +1,5 @@
|
||||
# Regular configuration file (can be used as base in other projects, runs in CI)
|
||||
|
||||
# NOTE: this config file is not used by pytest locally.
|
||||
# See comment in mypy.ini.dev for explanation.
|
||||
|
||||
# WARNING: when changing this file, consider doing the same with mypy.ini.dev
|
||||
|
||||
[mypy]
|
||||
allow_redefinition = True
|
||||
check_untyped_defs = True
|
||||
|
||||
30
mypy.ini.dev
30
mypy.ini.dev
@@ -1,30 +0,0 @@
|
||||
# Configuration file to use during development
|
||||
|
||||
# Changes of plugin code are not detected by mypy, so
|
||||
# incremental mode can be harmful during development
|
||||
# (mypy cache is not always invalidated).
|
||||
# However, incremental mode has to be supported by django-stubs,
|
||||
# thus another config (mypy.ini) is used in CI.
|
||||
# Incremental mode is recommended for regular usage.
|
||||
|
||||
# WARNING: when changing this file, consider doing the same with mypy.ini
|
||||
|
||||
[mypy]
|
||||
allow_redefinition = True
|
||||
check_untyped_defs = True
|
||||
ignore_missing_imports = True
|
||||
# Avoid caching between test runs
|
||||
incremental = False
|
||||
strict_optional = True
|
||||
show_traceback = True
|
||||
warn_no_return = False
|
||||
warn_unused_ignores = True
|
||||
warn_redundant_casts = True
|
||||
warn_unused_configs = True
|
||||
warn_unreachable = True
|
||||
|
||||
plugins =
|
||||
mypy_django_plugin.main
|
||||
|
||||
[mypy.plugins.django-stubs]
|
||||
django_settings_module = scripts.django_tests_settings
|
||||
@@ -1,9 +1,8 @@
|
||||
import builtins
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, Iterator, Optional, Set, Tuple, Type, Union
|
||||
from typing import TYPE_CHECKING, Any, Dict, Iterable, Iterator, Optional, Set, Tuple, Type, Union
|
||||
|
||||
from django.core.exceptions import FieldError
|
||||
from django.db import models
|
||||
@@ -39,7 +38,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
@contextmanager
|
||||
def temp_environ():
|
||||
def temp_environ() -> Iterator[None]:
|
||||
"""Allow the ability to set os.environ temporarily"""
|
||||
environ = dict(os.environ)
|
||||
try:
|
||||
@@ -56,19 +55,6 @@ def initialize_django(settings_module: str) -> Tuple["Apps", "LazySettings"]:
|
||||
# add current directory to sys.path
|
||||
sys.path.append(os.getcwd())
|
||||
|
||||
def noop_class_getitem(cls, key):
|
||||
return cls
|
||||
|
||||
from django.db import models
|
||||
|
||||
models.QuerySet.__class_getitem__ = classmethod(noop_class_getitem) # type: ignore
|
||||
models.Manager.__class_getitem__ = classmethod(noop_class_getitem) # type: ignore
|
||||
|
||||
# Define mypy builtins, to not cause NameError during setting up Django.
|
||||
# TODO: temporary/unpatch
|
||||
builtins.reveal_type = lambda _: None
|
||||
builtins.reveal_locals = lambda: None
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
|
||||
@@ -80,8 +66,8 @@ def initialize_django(settings_module: str) -> Tuple["Apps", "LazySettings"]:
|
||||
|
||||
apps.populate(settings.INSTALLED_APPS)
|
||||
|
||||
assert apps.apps_ready
|
||||
assert settings.configured
|
||||
assert apps.apps_ready, "Apps are not ready"
|
||||
assert settings.configured, "Settings are not configured"
|
||||
|
||||
return apps, settings
|
||||
|
||||
@@ -127,7 +113,7 @@ class DjangoContext:
|
||||
return model_cls
|
||||
return None
|
||||
|
||||
def get_model_fields(self, model_cls: Type[Model]) -> Iterator[Field]:
|
||||
def get_model_fields(self, model_cls: Type[Model]) -> Iterator["Field[Any, Any]"]:
|
||||
for field in model_cls._meta.get_fields():
|
||||
if isinstance(field, Field):
|
||||
yield field
|
||||
@@ -137,7 +123,9 @@ class DjangoContext:
|
||||
if isinstance(field, ForeignObjectRel):
|
||||
yield field
|
||||
|
||||
def get_field_lookup_exact_type(self, api: TypeChecker, field: Union[Field, ForeignObjectRel]) -> MypyType:
|
||||
def get_field_lookup_exact_type(
|
||||
self, api: TypeChecker, field: Union["Field[Any, Any]", ForeignObjectRel]
|
||||
) -> MypyType:
|
||||
if isinstance(field, (RelatedField, ForeignObjectRel)):
|
||||
related_model_cls = field.related_model
|
||||
primary_key_field = self.get_primary_key_field(related_model_cls)
|
||||
@@ -155,7 +143,7 @@ class DjangoContext:
|
||||
return AnyType(TypeOfAny.explicit)
|
||||
return helpers.get_private_descriptor_type(field_info, "_pyi_lookup_exact_type", is_nullable=field.null)
|
||||
|
||||
def get_primary_key_field(self, model_cls: Type[Model]) -> Field:
|
||||
def get_primary_key_field(self, model_cls: Type[Model]) -> "Field[Any, Any]":
|
||||
for field in model_cls._meta.get_fields():
|
||||
if isinstance(field, Field):
|
||||
if field.primary_key:
|
||||
@@ -258,11 +246,11 @@ class DjangoContext:
|
||||
def all_registered_model_class_fullnames(self) -> Set[str]:
|
||||
return {helpers.get_class_fullname(cls) for cls in self.all_registered_model_classes}
|
||||
|
||||
def get_attname(self, field: Field) -> str:
|
||||
def get_attname(self, field: "Field[Any, Any]") -> str:
|
||||
attname = field.attname
|
||||
return attname
|
||||
|
||||
def get_field_nullability(self, field: Union[Field, ForeignObjectRel], method: Optional[str]) -> bool:
|
||||
def get_field_nullability(self, field: Union["Field[Any, Any]", ForeignObjectRel], method: Optional[str]) -> bool:
|
||||
if method in ("values", "values_list"):
|
||||
return field.null
|
||||
|
||||
@@ -279,7 +267,9 @@ class DjangoContext:
|
||||
return True
|
||||
return nullable
|
||||
|
||||
def get_field_set_type(self, api: TypeChecker, field: Union[Field, ForeignObjectRel], *, method: str) -> MypyType:
|
||||
def get_field_set_type(
|
||||
self, api: TypeChecker, field: Union["Field[Any, Any]", ForeignObjectRel], *, method: str
|
||||
) -> MypyType:
|
||||
"""Get a type of __set__ for this specific Django field."""
|
||||
target_field = field
|
||||
if isinstance(field, ForeignKey):
|
||||
@@ -297,7 +287,9 @@ class DjangoContext:
|
||||
field_set_type = helpers.convert_any_to_type(field_set_type, argument_field_type)
|
||||
return field_set_type
|
||||
|
||||
def get_field_get_type(self, api: TypeChecker, field: Union[Field, ForeignObjectRel], *, method: str) -> MypyType:
|
||||
def get_field_get_type(
|
||||
self, api: TypeChecker, field: Union["Field[Any, Any]", ForeignObjectRel], *, method: str
|
||||
) -> MypyType:
|
||||
"""Get a type of __get__ for this specific Django field."""
|
||||
field_info = helpers.lookup_class_typeinfo(api, field.__class__)
|
||||
if field_info is None:
|
||||
@@ -321,14 +313,16 @@ class DjangoContext:
|
||||
else:
|
||||
return helpers.get_private_descriptor_type(field_info, "_pyi_private_get_type", is_nullable=is_nullable)
|
||||
|
||||
def get_field_related_model_cls(self, field: Union[RelatedField, ForeignObjectRel]) -> Optional[Type[Model]]:
|
||||
def get_field_related_model_cls(
|
||||
self, field: Union["RelatedField[Any, Any]", ForeignObjectRel]
|
||||
) -> Optional[Type[Model]]:
|
||||
if isinstance(field, RelatedField):
|
||||
related_model_cls = field.remote_field.model
|
||||
else:
|
||||
related_model_cls = field.field.model
|
||||
|
||||
if isinstance(related_model_cls, str):
|
||||
if related_model_cls == "self": # type: ignore[unreachable]
|
||||
if related_model_cls == "self": # type: ignore
|
||||
# same model
|
||||
related_model_cls = field.model
|
||||
elif "." not in related_model_cls:
|
||||
@@ -342,9 +336,9 @@ class DjangoContext:
|
||||
|
||||
def _resolve_field_from_parts(
|
||||
self, field_parts: Iterable[str], model_cls: Type[Model]
|
||||
) -> Union[Field, ForeignObjectRel]:
|
||||
) -> Union["Field[Any, Any]", ForeignObjectRel]:
|
||||
currently_observed_model = model_cls
|
||||
field: Union[Field, ForeignObjectRel, GenericForeignKey, None] = None
|
||||
field: Union["Field[Any, Any]", ForeignObjectRel, GenericForeignKey, None] = None
|
||||
for field_part in field_parts:
|
||||
if field_part == "pk":
|
||||
field = self.get_primary_key_field(currently_observed_model)
|
||||
@@ -364,7 +358,9 @@ class DjangoContext:
|
||||
assert isinstance(field, (Field, ForeignObjectRel))
|
||||
return field
|
||||
|
||||
def resolve_lookup_into_field(self, model_cls: Type[Model], lookup: str) -> Union[Field, ForeignObjectRel]:
|
||||
def resolve_lookup_into_field(
|
||||
self, model_cls: Type[Model], lookup: str
|
||||
) -> Union["Field[Any, Any]", ForeignObjectRel]:
|
||||
query = Query(model_cls)
|
||||
lookup_parts, field_parts, is_expression = query.solve_lookup_type(lookup)
|
||||
|
||||
|
||||
@@ -95,7 +95,10 @@ def lookup_fully_qualified_typeinfo(api: Union[TypeChecker, SemanticAnalyzer], f
|
||||
return node
|
||||
|
||||
|
||||
def lookup_class_typeinfo(api: TypeChecker, klass: type) -> Optional[TypeInfo]:
|
||||
def lookup_class_typeinfo(api: TypeChecker, klass: Optional[type]) -> Optional[TypeInfo]:
|
||||
if klass is None:
|
||||
return None
|
||||
|
||||
fullname = get_class_fullname(klass)
|
||||
field_info = lookup_fully_qualified_typeinfo(api, fullname)
|
||||
return field_info
|
||||
@@ -183,7 +186,7 @@ def get_private_descriptor_type(type_info: TypeInfo, private_field_name: str, is
|
||||
return AnyType(TypeOfAny.explicit)
|
||||
|
||||
|
||||
def get_field_lookup_exact_type(api: TypeChecker, field: Field) -> MypyType:
|
||||
def get_field_lookup_exact_type(api: TypeChecker, field: "Field[Any, Any]") -> MypyType:
|
||||
if isinstance(field, (RelatedField, ForeignObjectRel)):
|
||||
lookup_type_class = field.related_model
|
||||
rel_model_info = lookup_class_typeinfo(api, lookup_type_class)
|
||||
@@ -318,7 +321,7 @@ def resolve_string_attribute_value(attr_expr: Expression, django_context: "Djang
|
||||
member_name = attr_expr.name
|
||||
if isinstance(attr_expr.expr, NameExpr) and attr_expr.expr.fullname == "django.conf.settings":
|
||||
if hasattr(django_context.settings, member_name):
|
||||
return getattr(django_context.settings, member_name)
|
||||
return getattr(django_context.settings, member_name) # type: ignore
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import sys
|
||||
from functools import partial
|
||||
from typing import Callable, Dict, List, Optional, Tuple
|
||||
from typing import Callable, Dict, List, Optional, Tuple, Type
|
||||
|
||||
from django.db.models.fields.related import RelatedField
|
||||
from mypy.modulefinder import mypy_path
|
||||
@@ -72,7 +72,7 @@ class NewSemanalDjangoPlugin(Plugin):
|
||||
def _get_current_queryset_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(fullnames.QUERYSET_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault(
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault( # type: ignore[no-any-return]
|
||||
"queryset_bases", {fullnames.QUERYSET_CLASS_FULLNAME: 1}
|
||||
)
|
||||
else:
|
||||
@@ -81,7 +81,7 @@ class NewSemanalDjangoPlugin(Plugin):
|
||||
def _get_current_manager_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(fullnames.MANAGER_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault(
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault( # type: ignore[no-any-return]
|
||||
"manager_bases", {fullnames.MANAGER_CLASS_FULLNAME: 1}
|
||||
)
|
||||
else:
|
||||
@@ -90,7 +90,7 @@ class NewSemanalDjangoPlugin(Plugin):
|
||||
def _get_current_model_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(fullnames.MODEL_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault(
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault( # type: ignore[no-any-return]
|
||||
"model_bases", {fullnames.MODEL_CLASS_FULLNAME: 1}
|
||||
)
|
||||
else:
|
||||
@@ -99,7 +99,7 @@ class NewSemanalDjangoPlugin(Plugin):
|
||||
def _get_current_form_bases(self) -> Dict[str, int]:
|
||||
model_sym = self.lookup_fully_qualified(fullnames.BASEFORM_CLASS_FULLNAME)
|
||||
if model_sym is not None and isinstance(model_sym.node, TypeInfo):
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault(
|
||||
return helpers.get_django_metadata(model_sym.node).setdefault( # type: ignore[no-any-return]
|
||||
"baseform_bases",
|
||||
{
|
||||
fullnames.BASEFORM_CLASS_FULLNAME: 1,
|
||||
@@ -305,5 +305,5 @@ class NewSemanalDjangoPlugin(Plugin):
|
||||
return None
|
||||
|
||||
|
||||
def plugin(version):
|
||||
def plugin(version: str) -> Type[NewSemanalDjangoPlugin]:
|
||||
return NewSemanalDjangoPlugin
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import TYPE_CHECKING, Optional, Tuple, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, Optional, Tuple, Union, cast
|
||||
|
||||
from django.db.models.fields import AutoField, Field
|
||||
from django.db.models.fields.related import RelatedField
|
||||
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
||||
|
||||
def _get_current_field_from_assignment(
|
||||
ctx: FunctionContext, django_context: DjangoContext
|
||||
) -> Optional[Union[Field, ForeignObjectRel, "GenericForeignKey"]]:
|
||||
) -> Optional[Union["Field[Any, Any]", ForeignObjectRel, "GenericForeignKey"]]:
|
||||
outer_model_info = helpers.get_typechecker_api(ctx).scope.active_class()
|
||||
if outer_model_info is None or not helpers.is_model_subclass_info(outer_model_info, django_context):
|
||||
return None
|
||||
@@ -42,7 +42,7 @@ def _get_current_field_from_assignment(
|
||||
return current_field
|
||||
|
||||
|
||||
def reparametrize_related_field_type(related_field_type: Instance, set_type, get_type) -> Instance:
|
||||
def reparametrize_related_field_type(related_field_type: Instance, set_type: MypyType, get_type: MypyType) -> Instance:
|
||||
args = [
|
||||
helpers.convert_any_to_type(related_field_type.args[0], set_type),
|
||||
helpers.convert_any_to_type(related_field_type.args[1], get_type),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Optional, Union
|
||||
|
||||
from mypy.checker import TypeChecker, fill_typevars
|
||||
from mypy.checker import TypeChecker
|
||||
from mypy.nodes import (
|
||||
GDEF,
|
||||
CallExpr,
|
||||
@@ -19,6 +19,7 @@ from mypy.plugin import AttributeContext, DynamicClassDefContext, SemanticAnalyz
|
||||
from mypy.types import AnyType, CallableType, Instance, ProperType
|
||||
from mypy.types import Type as MypyType
|
||||
from mypy.types import TypeOfAny
|
||||
from mypy.typevars import fill_typevars
|
||||
from typing_extensions import Final
|
||||
|
||||
from mypy_django_plugin.lib import fullnames, helpers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Dict, List, Optional, Type, Union, cast
|
||||
from typing import Any, Dict, List, Optional, Type, Union, cast
|
||||
|
||||
from django.db.models import Manager, Model
|
||||
from django.db.models.fields import DateField, DateTimeField, Field
|
||||
@@ -166,7 +166,7 @@ class ModelClassInitializer:
|
||||
|
||||
return queryset_info
|
||||
|
||||
def run_with_model_cls(self, model_cls):
|
||||
def run_with_model_cls(self, model_cls: Type[Model]) -> None:
|
||||
raise NotImplementedError("Implement this in subclasses")
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ class AddDefaultPrimaryKey(ModelClassInitializer):
|
||||
|
||||
def create_autofield(
|
||||
self,
|
||||
auto_field: Field,
|
||||
auto_field: "Field[Any, Any]",
|
||||
dest_name: str,
|
||||
existing_field: bool,
|
||||
) -> None:
|
||||
@@ -394,7 +394,7 @@ class AddManagers(ModelClassInitializer):
|
||||
|
||||
return None
|
||||
|
||||
def get_dynamic_manager(self, fullname: str, manager: Manager) -> Optional[TypeInfo]:
|
||||
def get_dynamic_manager(self, fullname: str, manager: "Manager[Any]") -> Optional[TypeInfo]:
|
||||
"""
|
||||
Try to get a dynamically defined manager
|
||||
"""
|
||||
|
||||
@@ -3,6 +3,7 @@ line-length = 120
|
||||
include = '\.pyi?$'
|
||||
|
||||
[tool.isort]
|
||||
profile = 'black'
|
||||
line_length = 120
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
|
||||
@@ -7,5 +7,5 @@ addopts =
|
||||
-s
|
||||
-v
|
||||
--cache-clear
|
||||
--mypy-ini-file=./mypy.ini.dev
|
||||
--mypy-ini-file=mypy.ini
|
||||
--mypy-extension-hook=scripts.tests_extension_hook.django_plugin_hook
|
||||
|
||||
@@ -3,10 +3,10 @@ requests==2.28.1
|
||||
gitpython==3.1.27
|
||||
pre-commit==2.20.0
|
||||
pytest==7.1.2
|
||||
pytest-mypy-plugins==1.9.3
|
||||
pytest-mypy-plugins==1.10.0
|
||||
psycopg2-binary
|
||||
-e ./django_stubs_ext
|
||||
-e .[compatible-mypy]
|
||||
|
||||
# Overrides:
|
||||
mypy==0.961
|
||||
mypy==0.971
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Some errors occur for the test suite itself, and cannot be addressed via django-stubs. They should be ignored
|
||||
# using this constant.
|
||||
import re
|
||||
from typing import Any, Dict, List
|
||||
|
||||
IGNORED_MODULES = {
|
||||
"schema",
|
||||
@@ -56,7 +57,7 @@ EXTERNAL_MODULES = [
|
||||
"argon2",
|
||||
"xml.dom",
|
||||
]
|
||||
IGNORED_ERRORS = {
|
||||
IGNORED_ERRORS: Dict[str, List[Any]] = {
|
||||
"__common__": [
|
||||
*MOCK_OBJECTS,
|
||||
*EXTERNAL_MODULES,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import shutil
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from git import RemoteProgress, Repo
|
||||
from git.remote import RemoteProgress
|
||||
from git.repo import Repo
|
||||
|
||||
from scripts.paths import DJANGO_SOURCE_DIRECTORY
|
||||
|
||||
@@ -10,7 +11,9 @@ class ProgressPrinter(RemoteProgress):
|
||||
def line_dropped(self, line: str) -> None:
|
||||
print(line)
|
||||
|
||||
def update(self, op_code, cur_count, max_count=None, message=""):
|
||||
def update(
|
||||
self, op_code: int, cur_count: Union[str, float], max_count: Union[str, float, None] = None, message: str = ""
|
||||
) -> None:
|
||||
print(self._cur_line)
|
||||
|
||||
|
||||
@@ -22,7 +25,7 @@ def checkout_django_branch(django_version: str, commit_sha: Optional[str]) -> Re
|
||||
repo = Repo.clone_from(
|
||||
"https://github.com/django/django.git",
|
||||
DJANGO_SOURCE_DIRECTORY,
|
||||
progress=ProgressPrinter(),
|
||||
progress=ProgressPrinter(), # type: ignore
|
||||
branch=branch,
|
||||
depth=100,
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ from pytest_mypy_plugins.item import YamlTestItem
|
||||
def django_plugin_hook(test_item: YamlTestItem) -> None:
|
||||
custom_settings = test_item.parsed_test_data.get("custom_settings", "")
|
||||
installed_apps = test_item.parsed_test_data.get("installed_apps", None)
|
||||
monkeypatch = test_item.parsed_test_data.get("monkeypatch", False)
|
||||
|
||||
if installed_apps and custom_settings:
|
||||
raise ValueError('"installed_apps" and "custom_settings" are not compatible, please use one or the other')
|
||||
@@ -18,6 +19,9 @@ def django_plugin_hook(test_item: YamlTestItem) -> None:
|
||||
if "SECRET_KEY" not in custom_settings:
|
||||
custom_settings = 'SECRET_KEY = "1"\n' + custom_settings
|
||||
|
||||
if monkeypatch:
|
||||
custom_settings = "import django_stubs_ext\ndjango_stubs_ext.monkeypatch()\n" + custom_settings
|
||||
|
||||
django_settings_section = "\n[mypy.plugins.django-stubs]\n" "django_settings_module = mysettings"
|
||||
if not test_item.additional_mypy_config:
|
||||
test_item.additional_mypy_config = django_settings_section
|
||||
|
||||
@@ -5,7 +5,7 @@ import sys
|
||||
from argparse import ArgumentParser
|
||||
from collections import defaultdict
|
||||
from distutils import spawn
|
||||
from typing import Dict, List, Pattern, Union
|
||||
from typing import DefaultDict, List, Pattern, Union
|
||||
|
||||
from scripts.enabled_test_modules import EXTERNAL_MODULES, IGNORED_ERRORS, IGNORED_MODULES, MOCK_OBJECTS
|
||||
from scripts.git_helpers import checkout_django_branch
|
||||
@@ -18,8 +18,10 @@ DJANGO_COMMIT_REFS = {
|
||||
}
|
||||
DEFAULT_DJANGO_VERSION = "3.2"
|
||||
|
||||
_DictToSearch = DefaultDict[str, DefaultDict[Union[str, Pattern[str]], int]]
|
||||
|
||||
def get_unused_ignores(ignored_message_freq: Dict[str, Dict[Union[str, Pattern], int]]) -> List[str]:
|
||||
|
||||
def get_unused_ignores(ignored_message_freq: _DictToSearch) -> List[str]:
|
||||
unused_ignores = []
|
||||
for root_key, patterns in IGNORED_ERRORS.items():
|
||||
for pattern in patterns:
|
||||
@@ -30,7 +32,7 @@ def get_unused_ignores(ignored_message_freq: Dict[str, Dict[Union[str, Pattern],
|
||||
return unused_ignores
|
||||
|
||||
|
||||
def does_pattern_fit(pattern: Union[Pattern, str], line: str):
|
||||
def does_pattern_fit(pattern: Union[Pattern[str], str], line: str) -> bool:
|
||||
if isinstance(pattern, Pattern):
|
||||
if pattern.search(line):
|
||||
return True
|
||||
@@ -40,7 +42,7 @@ def does_pattern_fit(pattern: Union[Pattern, str], line: str):
|
||||
return False
|
||||
|
||||
|
||||
def is_ignored(line: str, test_folder_name: str, *, ignored_message_freqs: Dict[str, Dict[str, int]]) -> bool:
|
||||
def is_ignored(line: str, test_folder_name: str, *, ignored_message_freqs: _DictToSearch) -> bool:
|
||||
if "runtests" in line:
|
||||
return True
|
||||
|
||||
@@ -86,14 +88,14 @@ if __name__ == "__main__":
|
||||
mypy_executable = spawn.find_executable("mypy")
|
||||
mypy_argv = [mypy_executable, *mypy_options]
|
||||
completed = subprocess.run(
|
||||
mypy_argv,
|
||||
mypy_argv, # type: ignore
|
||||
env={"PYTHONPATH": str(tests_root), "TYPECHECK_TESTS": "1"},
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
output = completed.stdout.decode()
|
||||
|
||||
ignored_message_freqs = defaultdict(lambda: defaultdict(int))
|
||||
ignored_message_freqs: _DictToSearch = defaultdict(lambda: defaultdict(int))
|
||||
|
||||
sorted_lines = sorted(output.splitlines())
|
||||
for line in sorted_lines:
|
||||
|
||||
5
setup.py
5
setup.py
@@ -22,7 +22,7 @@ with open("README.md") as f:
|
||||
dependencies = [
|
||||
"mypy>=0.930",
|
||||
"django",
|
||||
"django-stubs-ext>=0.4.0",
|
||||
"django-stubs-ext>=0.6.0",
|
||||
"tomli",
|
||||
# Types:
|
||||
"typing-extensions",
|
||||
@@ -31,7 +31,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
extras_require = {
|
||||
"compatible-mypy": ["mypy>=0.930,<0.970"],
|
||||
"compatible-mypy": ["mypy>=0.930,<0.980"],
|
||||
}
|
||||
|
||||
setup(
|
||||
@@ -61,6 +61,7 @@ setup(
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Typing :: Typed",
|
||||
"Framework :: Django",
|
||||
"Framework :: Django :: 2.2",
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
- case: annotated_should_not_iterfere
|
||||
main: |
|
||||
from dataclasses import dataclass
|
||||
import sys
|
||||
if sys.version_info < (3, 9):
|
||||
from typing_extensions import Annotated
|
||||
else:
|
||||
from typing import Annotated
|
||||
from typing_extensions import Annotated
|
||||
|
||||
class IntegerType:
|
||||
def __init__(self, min_value: int, max_value: int) -> None:
|
||||
|
||||
@@ -58,8 +58,6 @@
|
||||
mypy_config: |
|
||||
[mypy.plugins.django-stubs]
|
||||
django_settings_module = mysettings
|
||||
env:
|
||||
- MYPYPATH=./extras
|
||||
files:
|
||||
- path: extras/extra_module.py
|
||||
content: |
|
||||
|
||||
Reference in New Issue
Block a user