Skip to content

Commit ec28ed7

Browse files
committed
Merge remote-tracking branch 'origin/master' into explicit-error-codes
2 parents 02fe712 + eff0fab commit ec28ed7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+845
-619
lines changed

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Check http://editorconfig.org for more information
2+
# This is the main config file for this project:
3+
root = true
4+
5+
[*]
6+
charset = utf-8
7+
end_of_line = lf
8+
insert_final_newline = true
9+
indent_style = space
10+
trim_trailing_whitespace = true
11+
12+
[*.{py, pyi}]
13+
indent_size = 4

.github/workflows/release.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
jobs:
8+
build-and-publish:
9+
runs-on: ubuntu-latest
10+
environment:
11+
name: release
12+
url: https://pypi.org/p/djangorestframework-stubs
13+
permissions:
14+
id-token: write
15+
steps:
16+
- name: Setup python to build package
17+
uses: actions/setup-python@v6
18+
with:
19+
python-version: '3.12'
20+
- name: Install build
21+
run: python -m pip install build
22+
- uses: actions/checkout@v5
23+
with:
24+
fetch-depth: 0
25+
- name: Build package
26+
run: python -m build
27+
- name: Publish to PyPI
28+
uses: pypa/[email protected]

.github/workflows/test.yml

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,34 @@ on:
66
- master
77
pull_request:
88
workflow_dispatch:
9+
schedule:
10+
# 15:41 UTC every day
11+
- cron: "41 15 * * *"
12+
13+
permissions:
14+
contents: read
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
18+
cancel-in-progress: true
919

1020
jobs:
1121
mypy-self-check:
1222
timeout-minutes: 10
1323
runs-on: ubuntu-latest
1424
strategy:
25+
fail-fast: false
1526
matrix:
16-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
27+
python-version: ['3.10', '3.11', '3.12', '3.13']
1728
steps:
18-
- uses: actions/checkout@v4
29+
- uses: actions/checkout@v5
1930
- name: Set up Python ${{ matrix.python-version }}
20-
uses: actions/setup-python@v4
31+
uses: actions/setup-python@v6
2132
with:
2233
python-version: ${{ matrix.python-version }}
2334
- name: Install dependencies
2435
run: |
25-
pip install -U pip setuptools wheel
36+
pip install -U pip "setuptools<79.0.0" wheel
2637
SETUPTOOLS_ENABLE_FEATURES=legacy-editable pip install -r ./requirements.txt
2738
- name: Run mypy on plugin code
2839
run: mypy --strict mypy_drf_plugin
@@ -35,47 +46,67 @@ jobs:
3546
timeout-minutes: 10
3647
runs-on: ubuntu-latest
3748
strategy:
49+
fail-fast: false
3850
matrix:
39-
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
51+
python-version: ['3.10', '3.11', '3.12', '3.13']
4052
steps:
41-
- uses: actions/checkout@v4
53+
- uses: actions/checkout@v5
4254
- name: Setup system dependencies
4355
run: |
4456
sudo apt-get update
4557
sudo apt-get install binutils libproj-dev gdal-bin
4658
- name: Set up Python ${{ matrix.python-version }}
47-
uses: actions/setup-python@v4
59+
uses: actions/setup-python@v6
4860
with:
4961
python-version: ${{ matrix.python-version }}
5062
- name: Install dependencies
5163
run: |
52-
pip install -U pip setuptools wheel
64+
pip install -U pip "setuptools<79.0.0" wheel
5365
SETUPTOOLS_ENABLE_FEATURES=legacy-editable pip install -r ./requirements.txt
5466
5567
- name: Run tests
56-
run: pytest
68+
# Suppress errors from other packages due to https://github.com/typeddjango/pytest-mypy-plugins/issues/134
69+
run: pytest --mypy-only-local-stub
5770

5871
stubtest:
5972
timeout-minutes: 10
6073
runs-on: ubuntu-latest
6174
strategy:
6275
matrix:
63-
python-version: ['3.12']
76+
python-version: ['3.13']
6477
fail-fast: false
6578
steps:
66-
- uses: actions/checkout@v4
79+
- uses: actions/checkout@v5
6780
- name: Setup system dependencies
6881
run: |
6982
sudo apt-get update
7083
sudo apt-get install binutils libproj-dev gdal-bin
7184
- name: Set up Python ${{ matrix.python-version }}
72-
uses: actions/setup-python@v4
85+
uses: actions/setup-python@v6
7386
with:
7487
python-version: ${{ matrix.python-version }}
7588
- name: Install dependencies
7689
run: |
77-
pip install -U pip setuptools wheel
90+
pip install -U pip "setuptools<79.0.0" wheel
7891
SETUPTOOLS_ENABLE_FEATURES=legacy-editable pip install -r ./requirements.txt
7992
8093
- name: Run stubtest
8194
run: bash ./scripts/stubtest.sh
95+
96+
build-and-check:
97+
runs-on: ubuntu-latest
98+
steps:
99+
- uses: actions/checkout@v5
100+
with:
101+
fetch-tags: true
102+
- uses: actions/setup-python@v6
103+
with:
104+
python-version: '3.13'
105+
- name: Install dependencies
106+
run: python3 -m pip install --upgrade build twine
107+
- name: Build
108+
run: |
109+
python3 -m build --sdist --wheel .
110+
- name: Check package metadata
111+
run: |
112+
twine check --strict dist/*

.pre-commit-config.yaml

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# See https://pre-commit.com for more information
22
# See https://pre-commit.com/hooks.html for more hooks
3-
default_language_version:
4-
python: python3.12
53
repos:
64
- repo: https://github.com/pre-commit/pre-commit-hooks
7-
rev: v4.4.0
5+
rev: v6.0.0
86
hooks:
97
- id: check-yaml
108
- id: trailing-whitespace
@@ -13,18 +11,15 @@ repos:
1311
- id: check-merge-conflict
1412
- id: end-of-file-fixer
1513
- repo: https://github.com/astral-sh/ruff-pre-commit
16-
rev: v0.0.292
14+
rev: v0.13.0
1715
hooks:
1816
- id: ruff
1917
args: ["--fix", "--exit-non-zero-on-fix"]
20-
- repo: https://github.com/psf/black
21-
rev: 23.9.1
22-
hooks:
23-
- id: black
18+
- id: ruff-format
2419

2520
ci:
26-
autofix_commit_msg: '[pre-commit.ci] auto fixes from pre-commit.com hooks'
27-
autofix_prs: true
28-
autoupdate_commit_msg: '[pre-commit.ci] pre-commit autoupdate'
29-
autoupdate_schedule: weekly
30-
submodules: false
21+
autofix_commit_msg: "[pre-commit.ci] auto fixes from pre-commit.com hooks"
22+
autofix_prs: true
23+
autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
24+
autoupdate_schedule: weekly
25+
submodules: false

CONTRIBUTING.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,13 @@ pytest
7979
Run `bash ./scripts/stubtest.sh` to test that stubs and sources are in-line.
8080

8181
We have two special files to allow errors:
82+
8283
1. `scripts/stubtest/allowlist.txt` where we store things that we really don't care about: hacks, DRF internal utility modules, things that are handled by our plugin, things that are not representable by type system, etc
8384
2. `scripts/stubtest/allowlist_todo.txt` where we store all errors there are right now. Basically, this is a TODO list: we need to work through this list and fix things (or move entries to real `allowlist.txt`). In the end, ideally we can remove this file
8485

8586
You might also want to disable `incremental` mode while working on `stubtest` changes.
8687
This mode leads to several known problems (stubs do not show up or have strange errors).
8788

88-
**Important**: right now we only run `stubtest` on Python 3.12 (because it is the latest released version at the moment), any other versions might generate different outputs. Any work to create per-version allowlists is welcome.
89-
9089
## Submission Guidelines
9190

9291
The workflow for contributions is fairly simple:
@@ -96,3 +95,30 @@ The workflow for contributions is fairly simple:
9695
3. make whatever changes you want to contribute.
9796
4. ensure your contribution does not introduce linting issues or breaks the tests by linting and testing the code.
9897
5. make a pull request with an adequate description.
98+
99+
## Releasing `djangorestframework-stubs`
100+
101+
1. Open a pull request that updates `setup.py` (anyone can open this PR, not just maintainers):
102+
103+
- Increase `version=` value within `setup(...)`. Version number `major.minor.patch` is formed as follows:
104+
105+
`major.minor` version must match newest supported `djangorestframework` release.
106+
107+
`patch` is sequentially increasing for each stubs release. Reset to `0` if `major.minor` was updated.
108+
109+
- Update `django-stubs>=` dependency to point to latest `django-stubs` release.
110+
- Use pull request title "Version x.y.z release" by convention.
111+
112+
2. Ensure the CI succeeds. A maintainer must merge this PR. If it's just a verison bump, no need
113+
to wait for a second maintainer's approval.
114+
115+
3. Maintainers need to [сreate a new GitHub release](https://github.com/typeddjango/djangorestframework-stubs/releases/new):
116+
117+
- Under "Choose a tag" enter the new version number. Do NOT use `v` prefix.
118+
- Click "Generate release notes".
119+
- Delete all release notes lines containing `by @pre-commit-ci` or `by @dependabot`, as these
120+
are irrelevant for our users.
121+
122+
4. Once you feel brave enough, click "Publish release".
123+
124+
5. Check that the [release workflow](https://github.com/typeddjango/djangorestframework-stubs/actions/workflows/release.yml) succeeds.

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
<img src="http://mypy-lang.org/static/mypy_light.svg" alt="mypy logo" width="300px"/>
1+
<img src="https://mypy-lang.org/static/mypy_light.svg" alt="mypy logo" width="300px"/>
22

33
# pep484 stubs for Django REST framework
44

5-
[![Build Status](https://travis-ci.com/typeddjango/djangorestframework-stubs.svg?branch=master)](https://travis-ci.com/typeddjango/djangorestframework-stubs)
6-
[![Checked with mypy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)
5+
[![test](https://github.com/typeddjango/djangorestframework-stubs/actions/workflows/test.yml/badge.svg?branch=master&event=push)](https://github.com/typeddjango/djangorestframework-stubs/actions/workflows/test.yml)
6+
[![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
77
[![Gitter](https://badges.gitter.im/mypy-django/Lobby.svg)](https://gitter.im/mypy-django/Lobby)
8+
[![StackOverflow](https://shields.io/badge/ask-stackoverflow-orange?logo=stackoverflow)](https://stackoverflow.com/questions/tagged/django-stubs?tab=Active)
89

910

1011
Mypy stubs for [Django REST Framework](https://pypi.org/project/djangorestframework/).
11-
Supports Python 3.8 and up.
12+
Supports Python 3.10 and up.
1213

1314
## Installation
1415

@@ -39,7 +40,7 @@ class MyModelSerializer(serializers.ModelSerializer[MyModel]):
3940
fields = ("id", "example")
4041
```
4142

42-
Which means that methods where the model is being passed around will know the actual type of the model instead of being `Any`. The `instance` attribute on the above serializer will be `Union[MyModel, typing.Sequence[MyModel], None]`.
43+
Which means that methods where the model is being passed around will know the actual type of the model instead of being `Any`. The `instance` attribute on the above serializer will be `MyModel | typing.Sequence[MyModel] | None`.
4344

4445
## To get help
4546

mypy.ini

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[mypy]
22
allow_redefinition = true
33
check_untyped_defs = true
4-
ignore_missing_imports = true
54
incremental = true
65
strict_optional = true
76
show_traceback = true
@@ -13,34 +12,10 @@ disallow_untyped_defs = true
1312
disallow_incomplete_defs = true
1413
disable_error_code = empty-body
1514
enable_error_code = ignore-without-code
16-
# TODO: update our test error messages to match new mypy output
17-
force_uppercase_builtins = true
18-
force_union_syntax = true
1915

2016
plugins =
2117
mypy_django_plugin.main,
2218
mypy_drf_plugin.main
2319

2420
[mypy.plugins.django-stubs]
2521
django_settings_module = scripts.drf_tests_settings
26-
27-
# Suppress errors from site-packages due to https://github.com/typeddjango/pytest-mypy-plugins/issues/134
28-
[mypy-uritemplate.*]
29-
warn_unreachable = false
30-
disable_error_code = ignore-without-code
31-
32-
[mypy-yaml.*]
33-
disallow_untyped_defs = false
34-
disallow_incomplete_defs = false
35-
36-
[mypy-urllib3.*]
37-
disallow_untyped_defs = false
38-
disallow_incomplete_defs = false
39-
40-
[mypy-requests.*]
41-
disallow_untyped_defs = false
42-
disallow_incomplete_defs = false
43-
44-
[mypy-markdown.*]
45-
disallow_untyped_defs = false
46-
disallow_incomplete_defs = false

mypy_drf_plugin/lib/helpers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from typing import Any, Dict
1+
from typing import Any
22

33
from mypy.nodes import TypeInfo
44

55

6-
def get_drf_metadata(info: TypeInfo) -> Dict[str, Any]:
6+
def get_drf_metadata(info: TypeInfo) -> dict[str, Any]:
77
return info.metadata.setdefault("drf", {})

mypy_drf_plugin/main.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Callable, Dict, Optional, Type
1+
from collections.abc import Callable
22

33
from mypy.nodes import TypeInfo
44
from mypy.plugin import ClassDefContext, Plugin
@@ -16,21 +16,21 @@ def transform_serializer_class(ctx: ClassDefContext) -> None:
1616

1717

1818
class NewSemanalDRFPlugin(Plugin):
19-
def _get_currently_defined_serializers(self) -> Dict[str, int]:
19+
def _get_currently_defined_serializers(self) -> dict[str, int]:
2020
base_serializer_sym = self.lookup_fully_qualified(fullnames.BASE_SERIALIZER_FULLNAME)
2121
if base_serializer_sym is not None and isinstance(base_serializer_sym.node, TypeInfo):
22-
serializer_bases: Dict[str, int] = base_serializer_sym.node.metadata.setdefault("drf", {}).setdefault(
22+
serializer_bases: dict[str, int] = base_serializer_sym.node.metadata.setdefault("drf", {}).setdefault(
2323
"serializer_bases", {fullnames.BASE_SERIALIZER_FULLNAME: 1}
2424
)
2525
return serializer_bases
2626
else:
2727
return {}
2828

29-
def get_base_class_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]:
29+
def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None:
3030
if fullname in self._get_currently_defined_serializers():
3131
return transform_serializer_class
3232
return None
3333

3434

35-
def plugin(version: str) -> Type[NewSemanalDRFPlugin]:
35+
def plugin(version: str) -> type[NewSemanalDRFPlugin]:
3636
return NewSemanalDRFPlugin

0 commit comments

Comments
 (0)