Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a fully locked test environment #1349

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ name = "attrs"
authors = [{ name = "Hynek Schlawack", email = "[email protected]" }]
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.8"
requires-python = ">=3.9"
description = "Classes Without Boilerplate"
keywords = ["class", "attribute", "boilerplate"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
Expand All @@ -28,29 +27,41 @@ classifiers = [
dependencies = []
dynamic = ["version", "readme"]

[project.optional-dependencies]
[project.urls]
Documentation = "https://www.attrs.org/"
Changelog = "https://www.attrs.org/en/stable/changelog.html"
GitHub = "https://github.com/python-attrs/attrs"
Funding = "https://github.com/sponsors/hynek"
Tidelift = "https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi"


[dependency-groups]
tests-mypy = [
'pytest-mypy-plugins; platform_python_implementation == "CPython" and python_version >= "3.10"',
# Since the mypy error messages keep changing, we have to keep updating this
# pin.
'mypy>=1.11.1; platform_python_implementation == "CPython" and python_version >= "3.10"',
]
tests = [
{ include-group = "tests-mypy" },
# For regression test to ensure cloudpickle compat doesn't break.
'cloudpickle; platform_python_implementation == "CPython"',
"hypothesis",
"pympler",
# 4.3.0 dropped last use of `convert`
"pytest>=4.3.0",
"pytest-xdist[psutil]",
"attrs[tests-mypy]",
]
cov = [
"attrs[tests]",
{ include-group = "tests" },
# Ensure coverage is new enough for `source_pkgs`.
"coverage[toml]>=5.3",
]
benchmark = ["pytest-codspeed", "pytest-xdist[psutil]", "attrs[tests]"]
pyright = ["pyright", { include-group = "tests" }]
benchmark = [
{ include-group = "tests" },
"pytest-codspeed",
"pytest-xdist[psutil]",
]
docs = [
"cogapp",
"furo",
Expand All @@ -59,17 +70,10 @@ docs = [
"sphinx-notfound-page",
"sphinxcontrib-towncrier",
# See https://github.com/sphinx-contrib/sphinxcontrib-towncrier/issues/92
# Pin also present in tox.ini
"towncrier<24.7",
]
dev = ["attrs[tests]", "pre-commit-uv"]

[project.urls]
Documentation = "https://www.attrs.org/"
Changelog = "https://www.attrs.org/en/stable/changelog.html"
GitHub = "https://github.com/python-attrs/attrs"
Funding = "https://github.com/sponsors/hynek"
Tidelift = "https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi"
docs-watch = [{ include-group = "docs" }, "watchfiles"]
dev = [{ include-group = "tests" }]


[tool.hatch.version]
Expand Down Expand Up @@ -227,6 +231,8 @@ ignore = [
"TD", # we don't follow other people's todo style
"TRY301", # I'm sorry, but this makes not sense for us.
"UP031", # format() is slow as molasses; % and f'' FTW.
"UP006", # replace Dict etc by dict etc later.
"UP035", # replace Dict etc by dict etc later.
]

[tool.ruff.lint.per-file-ignores]
Expand Down Expand Up @@ -254,10 +260,10 @@ ignore = [
"src/*/*.pyi" = ["ALL"] # TODO
"tests/test_annotations.py" = ["FA100"]
"tests/typing_example.py" = [
"E741", # ambiguous variable names don't matter in type checks
"B018", # useless expressions aren't useless in type checks
"B015", # pointless comparison in type checks aren't pointless
"UP037", # we test some older syntaxes on purpose
"E741", # ambiguous variable names don't matter in type checks
"B018", # useless expressions aren't useless in type checks
"B015", # pointless comparison in type checks aren't pointless
"UP037", # we test some older syntaxes on purpose
]

[tool.ruff.lint.isort]
Expand Down
1 change: 0 additions & 1 deletion src/attr/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@


PYPY = platform.python_implementation() == "PyPy"
PY_3_9_PLUS = sys.version_info[:2] >= (3, 9)
PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
PY_3_11_PLUS = sys.version_info[:2] >= (3, 11)
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
Expand Down
11 changes: 6 additions & 5 deletions src/attr/_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import copy

from ._compat import PY_3_9_PLUS, get_generic_base
from ._compat import get_generic_base
from ._make import _OBJ_SETATTR, NOTHING, fields
from .exceptions import AttrsAttributeNotFoundError

Expand Down Expand Up @@ -450,10 +450,11 @@ class yet.
if getattr(cls, "__attrs_types_resolved__", None) != cls:
import typing

kwargs = {"globalns": globalns, "localns": localns}

if PY_3_9_PLUS:
kwargs["include_extras"] = include_extras
kwargs = {
"globalns": globalns,
"localns": localns,
"include_extras": include_extras,
}

hints = typing.get_type_hints(cls, **kwargs)
for field in fields(cls) if attribs is None else attribs:
Expand Down
46 changes: 25 additions & 21 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
min_version = 4
env_list =
pre-commit,
py3{8,9,10,11,12,13}-tests,
py3{9,10,11,12,13}-tests,
py3{10,11,12,13}-mypy,
pypy3-tests,
pyright,
Expand All @@ -16,45 +16,46 @@ pass_env = SETUPTOOLS_SCM_PRETEND_VERSION


[testenv]
runner = uv-venv-lock-runner
package = wheel
wheel_build_env = .pkg
extras =
dependency_groups =
tests: tests
mypy: tests-mypy
commands =
tests: pytest {posargs:-n auto}
tests: pytest {posargs}
mypy: mypy tests/typing_example.py
mypy: mypy src/attrs/__init__.pyi src/attr/__init__.pyi src/attr/_typing_compat.pyi src/attr/_version_info.pyi src/attr/converters.pyi src/attr/exceptions.pyi src/attr/filters.pyi src/attr/setters.pyi src/attr/validators.pyi

[testenv:pypy3-tests]
extras = tests
dependency_groups = tests
commands = pytest tests/test_functional.py

[testenv:py3{8,10,13}-tests]
extras = cov
[testenv:py3{9,10,13}-tests]
dependency_groups = cov
# Python 3.6+ has a number of compile-time warnings on invalid string escapes.
# PYTHONWARNINGS=d makes them visible during the tox run.
set_env =
COVERAGE_PROCESS_START={toxinidir}/pyproject.toml
PYTHONWARNINGS=d
commands_pre = python -c 'import pathlib; pathlib.Path("{env_site_packages_dir}/cov.pth").write_text("import coverage; coverage.process_startup()")'
# We group xdist execution by file because otherwise the Mypy tests have race conditions.
commands = coverage run -m pytest {posargs:-n auto --dist loadfile}
commands =
coverage run -m pytest {posargs}

[testenv:coverage-report]
# Keep base_python in-sync with .python-version-default
base_python = py313
# Keep depends in-sync with testenv above that has cov extra.
depends = py3{8,10,13}-tests
# Keep depends in-sync with testenv above that has the cov dependency group.
depends = py3{9,10,13}-tests
skip_install = true
deps = coverage[toml]>=5.3
dependency_groups = cov
commands =
coverage combine
coverage report


[testenv:codspeed]
extras = benchmark
dependency_groups = benchmark
pass_env =
CODSPEED_TOKEN
CODSPEED_ENV
Expand All @@ -65,9 +66,10 @@ commands = pytest --codspeed -n auto bench/test_benchmarks.py


[testenv:docs-{build,doctests,linkcheck}]
# Keep base_python in sync with ci.yml/docs and .readthedocs.yaml.
runner = uv-venv-lock-runner
# Keep base_python in-sync with ci.yml/docs and .readthedocs.yaml.
base_python = py313
extras = docs
dependency_groups = docs
commands =
build: sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html
doctests: sphinx-build -n -T -W -b doctest -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html
Expand All @@ -76,46 +78,48 @@ commands =
[testenv:docs-watch]
package = editable
base_python = {[testenv:docs-build]base_python}
extras = {[testenv:docs-build]extras}
dependency_groups = docs-watch
deps = watchfiles
commands =
watchfiles \
--ignore-paths docs/_build/ \
'sphinx-build -W -n --jobs auto -b html -d {envtmpdir}/doctrees docs docs/_build/html' \
README.md \
src \
docs

[testenv:docs-sponsors]
runner = uv-venv-runner
skip_install = true
description = Ensure sponsor logos are up to date.
deps = cogapp
commands = cog -rP README.md docs/index.md


[testenv:pre-commit]
runner = uv-venv-runner
skip_install = true
deps = pre-commit-uv
commands = pre-commit run --all-files


[testenv:changelog]
# See https://github.com/sphinx-contrib/sphinxcontrib-towncrier/issues/92
# Pin also present in pyproject.toml
deps = towncrier<24.7
dependency_groups = docs
skip_install = true
commands =
towncrier --version
towncrier build --version main --draft


[testenv:pyright]
extras = tests
deps = pyright>=1.1.380
dependency_groups = pyright
commands = pytest tests/test_pyright.py -vv


[testenv:docset]
runner = uv-venv-runner
deps = doc2dash
extras = docs
dependency_groups = docs
allowlist_externals =
rm
cp
Expand Down
Loading
Loading