Based on pylint's message ``consider-iterating-dictionary`` suggestion.
Surprisingly using a dict or set comprehension instead of a new temp var is
actually consistently slower here, which was not intuitive for me.
```python
from timeit import timeit
families = {1: {"testcase": [1, 2, 3, 5, 8]}}
attrs = {1: "a", 2: "b", 3: "c", 4: "d", 5: "e", 6: "f", 7: "g", 8: "h"}
class Old:
def old(self):
self.attrs = attrs
temp_attrs = {}
for key in self.attrs.keys():
if key in families[1]["testcase"]:
temp_attrs[key] = self.attrs[key]
self.attrs = temp_attrs
class OldBis:
def old(self):
self.attrs = attrs
temp_attrs = {}
for key in self.attrs:
if key in families[1]["testcase"]:
temp_attrs[key] = self.attrs[key]
self.attrs = temp_attrs
class New:
def new(self):
self.attrs = attrs
self.attrs = { # Even worse with k: v for k in self.attrs.items()
k: self.attrs[k] for k in self.attrs if k in families[1]["testcase"]
}
if __name__ == "__main__":
n = 1000000
print(f"Old: {timeit(Old().old, number=n)}")
print(f"Just removing the keys(): {timeit(OldBis().old, number=n)}")
print(f"List comp, no temp var: {timeit(New().new, number=n)}")
```
Result:
Old: 0.9493889989680611
Just removing the keys(): 0.9042672360083088
List comp, no temp var: 0.9916125109884888
It's also true for the other example with similar benchmark, but the exact
code probably does not need to be in the commit message.
411 lines
12 KiB
TOML
411 lines
12 KiB
TOML
[project]
|
|
name = "pytest"
|
|
description = "pytest: simple powerful testing with Python"
|
|
readme = "README.rst"
|
|
keywords = [
|
|
"test",
|
|
"unittest",
|
|
]
|
|
license = {text = "MIT"}
|
|
authors = [
|
|
{name = "Holger Krekel"},
|
|
{name = "Bruno Oliveira"},
|
|
{name = "Ronny Pfannschmidt"},
|
|
{name = "Floris Bruynooghe"},
|
|
{name = "Brianna Laugher"},
|
|
{name = "Florian Bruhin"},
|
|
{name = "Others (See AUTHORS)"},
|
|
]
|
|
requires-python = ">=3.8"
|
|
classifiers = [
|
|
"Development Status :: 6 - Mature",
|
|
"Intended Audience :: Developers",
|
|
"License :: OSI Approved :: MIT License",
|
|
"Operating System :: MacOS",
|
|
"Operating System :: Microsoft :: Windows",
|
|
"Operating System :: POSIX",
|
|
"Operating System :: Unix",
|
|
"Programming Language :: Python :: 3 :: Only",
|
|
"Programming Language :: Python :: 3.8",
|
|
"Programming Language :: Python :: 3.9",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Topic :: Software Development :: Libraries",
|
|
"Topic :: Software Development :: Testing",
|
|
"Topic :: Utilities",
|
|
]
|
|
dynamic = [
|
|
"version",
|
|
]
|
|
dependencies = [
|
|
'colorama; sys_platform == "win32"',
|
|
'exceptiongroup>=1.0.0rc8; python_version < "3.11"',
|
|
"iniconfig",
|
|
"packaging",
|
|
"pluggy<2.0,>=1.4",
|
|
'tomli>=1; python_version < "3.11"',
|
|
]
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
"argcomplete",
|
|
"attrs>=19.2",
|
|
"hypothesis>=3.56",
|
|
"mock",
|
|
"pygments>=2.7.2",
|
|
"requests",
|
|
"setuptools",
|
|
"xmlschema",
|
|
]
|
|
[project.urls]
|
|
Changelog = "https://docs.pytest.org/en/stable/changelog.html"
|
|
Homepage = "https://docs.pytest.org/en/latest/"
|
|
Source = "https://github.com/pytest-dev/pytest"
|
|
Tracker = "https://github.com/pytest-dev/pytest/issues"
|
|
Twitter = "https://twitter.com/pytestdotorg"
|
|
[project.scripts]
|
|
"py.test" = "pytest:console_main"
|
|
pytest = "pytest:console_main"
|
|
|
|
[build-system]
|
|
build-backend = "setuptools.build_meta"
|
|
requires = [
|
|
"setuptools>=61",
|
|
"setuptools-scm[toml]>=6.2.3",
|
|
]
|
|
|
|
[tool.setuptools.package-data]
|
|
"_pytest" = ["py.typed"]
|
|
"pytest" = ["py.typed"]
|
|
|
|
[tool.setuptools_scm]
|
|
write_to = "src/_pytest/_version.py"
|
|
|
|
[tool.black]
|
|
target-version = ['py38']
|
|
|
|
[tool.ruff]
|
|
src = ["src"]
|
|
line-length = 88
|
|
|
|
[tool.ruff.format]
|
|
docstring-code-format = true
|
|
|
|
[tool.ruff.lint]
|
|
select = [
|
|
"B", # bugbear
|
|
"D", # pydocstyle
|
|
"E", # pycodestyle
|
|
"F", # pyflakes
|
|
"I", # isort
|
|
"PYI", # flake8-pyi
|
|
"UP", # pyupgrade
|
|
"RUF", # ruff
|
|
"W", # pycodestyle
|
|
"PIE", # flake8-pie
|
|
"PGH004", # pygrep-hooks - Use specific rule codes when using noqa
|
|
"PLE", # pylint error
|
|
"PLW", # pylint warning
|
|
"PLR1714", # Consider merging multiple comparisons
|
|
]
|
|
ignore = [
|
|
# bugbear ignore
|
|
"B004", # Using `hasattr(x, "__call__")` to test if x is callable is unreliable.
|
|
"B007", # Loop control variable `i` not used within loop body
|
|
"B009", # Do not call `getattr` with a constant attribute value
|
|
"B010", # [*] Do not call `setattr` with a constant attribute value.
|
|
"B011", # Do not `assert False` (`python -O` removes these calls)
|
|
"B028", # No explicit `stacklevel` keyword argument found
|
|
# pycodestyle ignore
|
|
# pytest can do weird low-level things, and we usually know
|
|
# what we're doing when we use type(..) is ...
|
|
"E721", # Do not compare types, use `isinstance()`
|
|
# pydocstyle ignore
|
|
"D100", # Missing docstring in public module
|
|
"D101", # Missing docstring in public class
|
|
"D102", # Missing docstring in public method
|
|
"D103", # Missing docstring in public function
|
|
"D104", # Missing docstring in public package
|
|
"D105", # Missing docstring in magic method
|
|
"D106", # Missing docstring in public nested class
|
|
"D107", # Missing docstring in `__init__`
|
|
"D209", # [*] Multi-line docstring closing quotes should be on a separate line
|
|
"D205", # 1 blank line required between summary line and description
|
|
"D400", # First line should end with a period
|
|
"D401", # First line of docstring should be in imperative mood
|
|
"D402", # First line should not be the function's signature
|
|
"D404", # First word of the docstring should not be "This"
|
|
"D415", # First line should end with a period, question mark, or exclamation point
|
|
# ruff ignore
|
|
"RUF012", # Mutable class attributes should be annotated with `typing.ClassVar`
|
|
# pylint ignore
|
|
"PLW0603", # Using the global statement
|
|
"PLW0120", # remove the else and dedent its contents
|
|
"PLW2901", # for loop variable overwritten by assignment target
|
|
"PLR5501", # Use `elif` instead of `else` then `if`
|
|
]
|
|
|
|
[tool.ruff.lint.pycodestyle]
|
|
# In order to be able to format for 88 char in ruff format
|
|
max-line-length = 120
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "pep257"
|
|
|
|
[tool.ruff.lint.isort]
|
|
force-single-line = true
|
|
combine-as-imports = true
|
|
force-sort-within-sections = true
|
|
order-by-type = false
|
|
known-local-folder = ["pytest", "_pytest"]
|
|
lines-after-imports = 2
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"src/_pytest/_py/**/*.py" = ["B", "PYI"]
|
|
"src/_pytest/_version.py" = ["I001"]
|
|
"testing/python/approx.py" = ["B015"]
|
|
|
|
[tool.pylint.main]
|
|
# Maximum number of characters on a single line.
|
|
max-line-length = 120
|
|
disable= [
|
|
"abstract-method",
|
|
"arguments-differ",
|
|
"arguments-renamed",
|
|
"assigning-non-slot",
|
|
"attribute-defined-outside-init",
|
|
"bad-classmethod-argument",
|
|
"bad-mcs-method-argument",
|
|
"broad-exception-caught",
|
|
"broad-exception-raised",
|
|
"cell-var-from-loop",
|
|
"comparison-of-constants",
|
|
"comparison-with-callable",
|
|
"comparison-with-itself",
|
|
"condition-evals-to-constant",
|
|
"consider-using-dict-items",
|
|
"consider-using-enumerate",
|
|
"consider-using-from-import",
|
|
"consider-using-f-string",
|
|
"consider-using-in",
|
|
"consider-using-sys-exit",
|
|
"consider-using-ternary",
|
|
"consider-using-with",
|
|
"cyclic-import",
|
|
"disallowed-name",
|
|
"duplicate-code",
|
|
"eval-used",
|
|
"exec-used",
|
|
"expression-not-assigned",
|
|
"fixme",
|
|
"global-statement",
|
|
"implicit-str-concat",
|
|
"import-error",
|
|
"import-outside-toplevel",
|
|
"inconsistent-return-statements",
|
|
"invalid-bool-returned",
|
|
"invalid-name",
|
|
"invalid-repr-returned",
|
|
"invalid-str-returned",
|
|
"keyword-arg-before-vararg",
|
|
"line-too-long",
|
|
"method-hidden",
|
|
"misplaced-bare-raise",
|
|
"missing-docstring",
|
|
"missing-timeout",
|
|
"multiple-statements",
|
|
"no-else-break",
|
|
"no-else-continue",
|
|
"no-else-raise",
|
|
"no-else-return",
|
|
"no-member",
|
|
"no-name-in-module",
|
|
"no-self-argument",
|
|
"not-an-iterable",
|
|
"not-callable",
|
|
"pointless-exception-statement",
|
|
"pointless-statement",
|
|
"pointless-string-statement",
|
|
"protected-access",
|
|
"raise-missing-from",
|
|
"redefined-argument-from-local",
|
|
"redefined-builtin",
|
|
"redefined-outer-name",
|
|
"reimported",
|
|
"simplifiable-condition",
|
|
"simplifiable-if-expression",
|
|
"singleton-comparison",
|
|
"superfluous-parens",
|
|
"super-init-not-called",
|
|
"too-few-public-methods",
|
|
"too-many-ancestors",
|
|
"too-many-arguments",
|
|
"too-many-branches",
|
|
"too-many-function-args",
|
|
"too-many-instance-attributes",
|
|
"too-many-lines",
|
|
"too-many-locals",
|
|
"too-many-nested-blocks",
|
|
"too-many-public-methods",
|
|
"too-many-return-statements",
|
|
"too-many-statements",
|
|
"try-except-raise",
|
|
"typevar-name-incorrect-variance",
|
|
"unbalanced-tuple-unpacking",
|
|
"undefined-loop-variable",
|
|
"undefined-variable",
|
|
"unexpected-keyword-arg",
|
|
"unidiomatic-typecheck",
|
|
"unnecessary-comprehension",
|
|
"unnecessary-dunder-call",
|
|
"unnecessary-lambda",
|
|
"unnecessary-lambda-assignment",
|
|
"unpacking-non-sequence",
|
|
"unspecified-encoding",
|
|
"unsubscriptable-object",
|
|
"unused-argument",
|
|
"unused-import",
|
|
"unused-variable",
|
|
"used-before-assignment",
|
|
"use-dict-literal",
|
|
"use-implicit-booleaness-not-comparison",
|
|
"use-implicit-booleaness-not-len",
|
|
"useless-else-on-loop",
|
|
"useless-import-alias",
|
|
"useless-return",
|
|
"use-maxsplit-arg",
|
|
"using-constant-test",
|
|
"wrong-import-order",
|
|
]
|
|
|
|
[tool.check-wheel-contents]
|
|
# check-wheel-contents is executed by the build-and-inspect-python-package action.
|
|
# W009: Wheel contains multiple toplevel library entries
|
|
ignore = "W009"
|
|
|
|
[tool.pyproject-fmt]
|
|
indent = 4
|
|
|
|
[tool.pytest.ini_options]
|
|
minversion = "2.0"
|
|
addopts = "-rfEX -p pytester --strict-markers"
|
|
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
|
|
python_classes = ["Test", "Acceptance"]
|
|
python_functions = ["test"]
|
|
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".
|
|
testpaths = ["testing"]
|
|
norecursedirs = [
|
|
"testing/example_scripts",
|
|
".*",
|
|
"build",
|
|
"dist",
|
|
]
|
|
xfail_strict = true
|
|
filterwarnings = [
|
|
"error",
|
|
"default:Using or importing the ABCs:DeprecationWarning:unittest2.*",
|
|
# produced by older pyparsing<=2.2.0.
|
|
"default:Using or importing the ABCs:DeprecationWarning:pyparsing.*",
|
|
"default:the imp module is deprecated in favour of importlib:DeprecationWarning:nose.*",
|
|
# distutils is deprecated in 3.10, scheduled for removal in 3.12
|
|
"ignore:The distutils package is deprecated:DeprecationWarning",
|
|
# produced by pytest-xdist
|
|
"ignore:.*type argument to addoption.*:DeprecationWarning",
|
|
# produced on execnet (pytest-xdist)
|
|
"ignore:.*inspect.getargspec.*deprecated, use inspect.signature.*:DeprecationWarning",
|
|
# pytest's own futurewarnings
|
|
"ignore::pytest.PytestExperimentalApiWarning",
|
|
# Do not cause SyntaxError for invalid escape sequences in py37.
|
|
# Those are caught/handled by pyupgrade, and not easy to filter with the
|
|
# module being the filename (with .py removed).
|
|
"default:invalid escape sequence:DeprecationWarning",
|
|
# ignore not yet fixed warnings for hook markers
|
|
"default:.*not marked using pytest.hook.*",
|
|
"ignore:.*not marked using pytest.hook.*::xdist.*",
|
|
# ignore use of unregistered marks, because we use many to test the implementation
|
|
"ignore::_pytest.warning_types.PytestUnknownMarkWarning",
|
|
# https://github.com/benjaminp/six/issues/341
|
|
"ignore:_SixMetaPathImporter\\.exec_module\\(\\) not found; falling back to load_module\\(\\):ImportWarning",
|
|
# https://github.com/benjaminp/six/pull/352
|
|
"ignore:_SixMetaPathImporter\\.find_spec\\(\\) not found; falling back to find_module\\(\\):ImportWarning",
|
|
# https://github.com/pypa/setuptools/pull/2517
|
|
"ignore:VendorImporter\\.find_spec\\(\\) not found; falling back to find_module\\(\\):ImportWarning",
|
|
# https://github.com/pytest-dev/execnet/pull/127
|
|
"ignore:isSet\\(\\) is deprecated, use is_set\\(\\) instead:DeprecationWarning",
|
|
]
|
|
pytester_example_dir = "testing/example_scripts"
|
|
markers = [
|
|
# dummy markers for testing
|
|
"foo",
|
|
"bar",
|
|
"baz",
|
|
# conftest.py reorders tests moving slow ones to the end of the list
|
|
"slow",
|
|
# experimental mark for all tests using pexpect
|
|
"uses_pexpect",
|
|
]
|
|
|
|
[tool.towncrier]
|
|
package = "pytest"
|
|
package_dir = "src"
|
|
filename = "doc/en/changelog.rst"
|
|
directory = "changelog/"
|
|
title_format = "pytest {version} ({project_date})"
|
|
template = "changelog/_template.rst"
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "breaking"
|
|
name = "Breaking Changes"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "deprecation"
|
|
name = "Deprecations"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "feature"
|
|
name = "Features"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "improvement"
|
|
name = "Improvements"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "bugfix"
|
|
name = "Bug Fixes"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "vendor"
|
|
name = "Vendored Libraries"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "doc"
|
|
name = "Improved Documentation"
|
|
showcontent = true
|
|
|
|
[[tool.towncrier.type]]
|
|
directory = "trivial"
|
|
name = "Trivial/Internal Changes"
|
|
showcontent = true
|
|
|
|
[tool.mypy]
|
|
files = ["src", "testing", "scripts"]
|
|
mypy_path = ["src"]
|
|
check_untyped_defs = true
|
|
disallow_any_generics = true
|
|
disallow_untyped_defs = true
|
|
ignore_missing_imports = true
|
|
show_error_codes = true
|
|
strict_equality = true
|
|
warn_redundant_casts = true
|
|
warn_return_any = true
|
|
warn_unreachable = true
|
|
warn_unused_configs = true
|
|
no_implicit_reexport = true
|
|
warn_unused_ignores = true
|