aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/attrs/py3
diff options
context:
space:
mode:
authorAlexSm <alex@ydb.tech>2024-01-18 11:28:56 +0100
committerGitHub <noreply@github.com>2024-01-18 11:28:56 +0100
commit9d0a3761b3201e0d9db879a7adf91876ebdb0564 (patch)
tree541d11ac878c18efd7ebca81e35112aa0fef995b /contrib/python/attrs/py3
parent404ef8886ecc9736bc58ade6da2fbd83b486a408 (diff)
downloadydb-9d0a3761b3201e0d9db879a7adf91876ebdb0564.tar.gz
Library import 8 (#1074)
* Library import 8 * Add contrib/libs/cxxsupp/libcxx/include/__verbose_abort
Diffstat (limited to 'contrib/python/attrs/py3')
-rw-r--r--contrib/python/attrs/py3/.dist-info/METADATA101
-rw-r--r--contrib/python/attrs/py3/README.md38
-rw-r--r--contrib/python/attrs/py3/attr/__init__.py20
-rw-r--r--contrib/python/attrs/py3/attr/_cmp.py11
-rw-r--r--contrib/python/attrs/py3/attr/_compat.py116
-rw-r--r--contrib/python/attrs/py3/attr/_config.py4
-rw-r--r--contrib/python/attrs/py3/attr/_funcs.py82
-rw-r--r--contrib/python/attrs/py3/attr/_make.py648
-rw-r--r--contrib/python/attrs/py3/attr/_next_gen.py21
-rw-r--r--contrib/python/attrs/py3/attr/converters.py16
-rw-r--r--contrib/python/attrs/py3/attr/exceptions.py6
-rw-r--r--contrib/python/attrs/py3/attr/validators.py121
-rw-r--r--contrib/python/attrs/py3/attrs/converters.py2
-rw-r--r--contrib/python/attrs/py3/attrs/exceptions.py2
-rw-r--r--contrib/python/attrs/py3/attrs/filters.py2
-rw-r--r--contrib/python/attrs/py3/attrs/setters.py2
-rw-r--r--contrib/python/attrs/py3/attrs/validators.py2
-rw-r--r--contrib/python/attrs/py3/ya.make2
18 files changed, 566 insertions, 630 deletions
diff --git a/contrib/python/attrs/py3/.dist-info/METADATA b/contrib/python/attrs/py3/.dist-info/METADATA
index 4a986f007f..c20be76c74 100644
--- a/contrib/python/attrs/py3/.dist-info/METADATA
+++ b/contrib/python/attrs/py3/.dist-info/METADATA
@@ -1,11 +1,10 @@
Metadata-Version: 2.1
Name: attrs
-Version: 23.1.0
+Version: 23.2.0
Summary: Classes Without Boilerplate
Project-URL: Documentation, https://www.attrs.org/
Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html
-Project-URL: Bug Tracker, https://github.com/python-attrs/attrs/issues
-Project-URL: Source Code, https://github.com/python-attrs/attrs
+Project-URL: GitHub, https://github.com/python-attrs/attrs
Project-URL: Funding, https://github.com/sponsors/hynek
Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi
Author-email: Hynek Schlawack <hs@ox.cx>
@@ -13,13 +12,13 @@ License-Expression: MIT
License-File: LICENSE
Keywords: attribute,boilerplate,class
Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Typing :: Typed
@@ -29,7 +28,7 @@ Provides-Extra: cov
Requires-Dist: attrs[tests]; extra == 'cov'
Requires-Dist: coverage[toml]>=5.3; extra == 'cov'
Provides-Extra: dev
-Requires-Dist: attrs[docs,tests]; extra == 'dev'
+Requires-Dist: attrs[tests]; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Provides-Extra: docs
Requires-Dist: furo; extra == 'docs'
@@ -42,12 +41,14 @@ Requires-Dist: zope-interface; extra == 'docs'
Provides-Extra: tests
Requires-Dist: attrs[tests-no-zope]; extra == 'tests'
Requires-Dist: zope-interface; extra == 'tests'
+Provides-Extra: tests-mypy
+Requires-Dist: mypy>=1.6; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy'
Provides-Extra: tests-no-zope
-Requires-Dist: cloudpickle; platform_python_implementation == 'CPython' and extra == 'tests-no-zope'
+Requires-Dist: attrs[tests-mypy]; extra == 'tests-no-zope'
+Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests-no-zope'
Requires-Dist: hypothesis; extra == 'tests-no-zope'
-Requires-Dist: mypy>=1.1.1; platform_python_implementation == 'CPython' and extra == 'tests-no-zope'
Requires-Dist: pympler; extra == 'tests-no-zope'
-Requires-Dist: pytest-mypy-plugins; platform_python_implementation == 'CPython' and python_version < '3.11' and extra == 'tests-no-zope'
Requires-Dist: pytest-xdist[psutil]; extra == 'tests-no-zope'
Requires-Dist: pytest>=4.3.0; extra == 'tests-no-zope'
Description-Content-Type: text/markdown
@@ -71,21 +72,9 @@ Its main goal is to help you to write **concise** and **correct** software witho
Especially those generously supporting us at the *The Organization* tier and higher:
<p align="center">
- <a href="https://www.variomedia.de/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Variomedia.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Tidelift.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://sentry.io/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Sentry.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://filepreviews.io/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/FilePreviews.svg" width="200" height="60"></img>
- </a>
+ <a href="https://www.variomedia.de/"><img src="https://www.attrs.org/en/23.2.0/_static/sponsors/Variomedia.svg" width="200" height="60" /></a>
+ <a href="https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo"><img src="https://www.attrs.org/en/23.2.0/_static/sponsors/Tidelift.svg" width="200" height="60" /></a>
+ <a href="https://filepreviews.io/"><img src="https://www.attrs.org/en/23.2.0/_static/sponsors/FilePreviews.svg" width="200" height="60"/></a>
</p>
<p align="center">
@@ -161,7 +150,7 @@ Please check out [*On The Core API Names*](https://www.attrs.org/en/latest/names
On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).
In practice it does a lot more and is more flexible.
-For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), or allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization).
+For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), and allows for stepping through the generated methods using a debugger.
For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes).
@@ -174,9 +163,7 @@ For more details, please refer to our [comparison page](https://www.attrs.org/en
- [**Source Code**](https://github.com/python-attrs/attrs)
- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)
- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)
-- **License**: [MIT](https://www.attrs.org/en/latest/license.html)
- **Get Help**: please use the `python-attrs` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/python-attrs)
-- **Supported Python Versions**: 3.7 and later
### *attrs* for Enterprise
@@ -189,53 +176,25 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
## Release Information
-### Backwards-incompatible Changes
-
-- Python 3.6 has been dropped and packaging switched to static package data using [Hatch](https://hatch.pypa.io/latest/).
- [#993](https://github.com/python-attrs/attrs/issues/993)
-
-
-### Deprecations
-
-- The support for *zope-interface* via the `attrs.validators.provides` validator is now deprecated and will be removed in, or after, April 2024.
-
- The presence of a C-based package in our developement dependencies has caused headaches and we're not under the impression it's used a lot.
-
- Let us know if you're using it and we might publish it as a separate package.
- [#1120](https://github.com/python-attrs/attrs/issues/1120)
-
-
### Changes
-- `attrs.filters.exclude()` and `attrs.filters.include()` now support the passing of attribute names as strings.
- [#1068](https://github.com/python-attrs/attrs/issues/1068)
-- `attrs.has()` and `attrs.fields()` now handle generic classes correctly.
- [#1079](https://github.com/python-attrs/attrs/issues/1079)
-- Fix frozen exception classes when raised within e.g. `contextlib.contextmanager`, which mutates their `__traceback__` attributes.
- [#1081](https://github.com/python-attrs/attrs/issues/1081)
-- `@frozen` now works with type checkers that implement [PEP-681](https://peps.python.org/pep-0681/) (ex. [pyright](https://github.com/microsoft/pyright/)).
- [#1084](https://github.com/python-attrs/attrs/issues/1084)
-- Restored ability to unpickle instances pickled before 22.2.0.
- [#1085](https://github.com/python-attrs/attrs/issues/1085)
-- `attrs.asdict()`'s and `attrs.astuple()`'s type stubs now accept the `attrs.AttrsInstance` protocol.
- [#1090](https://github.com/python-attrs/attrs/issues/1090)
-- Fix slots class cellvar updating closure in CPython 3.8+ even when `__code__` introspection is unavailable.
- [#1092](https://github.com/python-attrs/attrs/issues/1092)
-- `attrs.resolve_types()` can now pass `include_extras` to `typing.get_type_hints()` on Python 3.9+, and does so by default.
- [#1099](https://github.com/python-attrs/attrs/issues/1099)
-- Added instructions for pull request workflow to `CONTRIBUTING.md`.
- [#1105](https://github.com/python-attrs/attrs/issues/1105)
-- Added *type* parameter to `attrs.field()` function for use with `attrs.make_class()`.
-
- Please note that type checkers ignore type metadata passed into `make_class()`, but it can be useful if you're wrapping _attrs_.
- [#1107](https://github.com/python-attrs/attrs/issues/1107)
-- It is now possible for `attrs.evolve()` (and `attr.evolve()`) to change fields named `inst` if the instance is passed as a positional argument.
-
- Passing the instance using the `inst` keyword argument is now deprecated and will be removed in, or after, April 2024.
- [#1117](https://github.com/python-attrs/attrs/issues/1117)
-- `attrs.validators.optional()` now also accepts a tuple of validators (in addition to lists of validators).
- [#1122](https://github.com/python-attrs/attrs/issues/1122)
-
+- The type annotation for `attrs.resolve_types()` is now correct.
+ [#1141](https://github.com/python-attrs/attrs/issues/1141)
+- Type stubs now use `typing.dataclass_transform` to decorate dataclass-like decorators, instead of the non-standard `__dataclass_transform__` special form, which is only supported by Pyright.
+ [#1158](https://github.com/python-attrs/attrs/issues/1158)
+- Fixed serialization of namedtuple fields using `attrs.asdict/astuple()` with `retain_collection_types=True`.
+ [#1165](https://github.com/python-attrs/attrs/issues/1165)
+- `attrs.AttrsInstance` is now a `typing.Protocol` in both type hints and code.
+ This allows you to subclass it along with another `Protocol`.
+ [#1172](https://github.com/python-attrs/attrs/issues/1172)
+- If *attrs* detects that `__attrs_pre_init__` accepts more than just `self`, it will call it with the same arguments as `__init__` was called.
+ This allows you to, for example, pass arguments to `super().__init__()`.
+ [#1187](https://github.com/python-attrs/attrs/issues/1187)
+- Slotted classes now transform `functools.cached_property` decorated methods to support equivalent semantics.
+ [#1200](https://github.com/python-attrs/attrs/issues/1200)
+- Added *class_body* argument to `attrs.make_class()` to provide additional attributes for newly created classes.
+ It is, for example, now possible to attach methods.
+ [#1203](https://github.com/python-attrs/attrs/issues/1203)
---
diff --git a/contrib/python/attrs/py3/README.md b/contrib/python/attrs/py3/README.md
index 2f5b223bfd..6ef8c0204e 100644
--- a/contrib/python/attrs/py3/README.md
+++ b/contrib/python/attrs/py3/README.md
@@ -8,19 +8,11 @@
</p>
<p align="center">
- <a href="https://www.attrs.org/en/stable/">
- <img src="https://img.shields.io/badge/Docs-RTD-black" alt="Documentation" />
- </a>
- <a href="https://github.com/python-attrs/attrs/blob/main/LICENSE">
- <img src="https://img.shields.io/badge/license-MIT-C06524" alt="License: MIT" />
- </a>
+ <a href="https://www.attrs.org/en/stable/"><img src="https://img.shields.io/badge/Docs-RTD-black" alt="Documentation" /></a>
+ <a href="https://github.com/python-attrs/attrs/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-C06524" alt="License: MIT" /></a>
<a href="https://bestpractices.coreinfrastructure.org/projects/6482"><img src="https://bestpractices.coreinfrastructure.org/projects/6482/badge"></a>
- <a href="https://pypi.org/project/attrs/">
- <img src="https://img.shields.io/pypi/v/attrs" />
- </a>
- <a href="https://pepy.tech/project/attrs">
- <img src="https://static.pepy.tech/personalized-badge/attrs?period=month&units=international_system&left_color=grey&right_color=blue&left_text=Downloads%20/%20Month" alt="Downloads per month" />
- </a>
+ <a href="https://pypi.org/project/attrs/"><img src="https://img.shields.io/pypi/v/attrs" /></a>
+ <a href="https://pepy.tech/project/attrs"><img src="https://static.pepy.tech/personalized-badge/attrs?period=month&units=international_system&left_color=grey&right_color=blue&left_text=Downloads%20/%20Month" alt="Downloads per month" /></a>
<a href="https://zenodo.org/badge/latestdoi/29918975"><img src="https://zenodo.org/badge/29918975.svg" alt="DOI"></a>
</p>
@@ -38,21 +30,9 @@ Its main goal is to help you to write **concise** and **correct** software witho
Especially those generously supporting us at the *The Organization* tier and higher:
<p align="center">
- <a href="https://www.variomedia.de/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Variomedia.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Tidelift.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://sentry.io/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/Sentry.svg" width="200" height="60"></img>
- </a>
-
- <a href="https://filepreviews.io/">
- <img src="https://raw.githubusercontent.com/python-attrs/attrs/main/.github/sponsors/FilePreviews.svg" width="200" height="60"></img>
- </a>
+ <a href="https://www.variomedia.de/"><img src="https://www.attrs.org/en/latest/_static/sponsors/Variomedia.svg" width="200" height="60" /></a>
+ <a href="https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo"><img src="https://www.attrs.org/en/latest/_static/sponsors/Tidelift.svg" width="200" height="60" /></a>
+ <a href="https://filepreviews.io/"><img src="https://www.attrs.org/en/latest/_static/sponsors/FilePreviews.svg" width="200" height="60"/></a>
</p>
<p align="center">
@@ -128,7 +108,7 @@ Please check out [*On The Core API Names*](https://www.attrs.org/en/latest/names
On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).
In practice it does a lot more and is more flexible.
-For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), or allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization).
+For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), and allows for stepping through the generated methods using a debugger.
For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes).
@@ -141,9 +121,7 @@ For more details, please refer to our [comparison page](https://www.attrs.org/en
- [**Source Code**](https://github.com/python-attrs/attrs)
- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)
- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)
-- **License**: [MIT](https://www.attrs.org/en/latest/license.html)
- **Get Help**: please use the `python-attrs` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/python-attrs)
-- **Supported Python Versions**: 3.7 and later
### *attrs* for Enterprise
diff --git a/contrib/python/attrs/py3/attr/__init__.py b/contrib/python/attrs/py3/attr/__init__.py
index 7cfa792f74..9226258a2d 100644
--- a/contrib/python/attrs/py3/attr/__init__.py
+++ b/contrib/python/attrs/py3/attr/__init__.py
@@ -9,6 +9,7 @@ from typing import Callable
from . import converters, exceptions, filters, setters, validators
from ._cmp import cmp_using
+from ._compat import Protocol
from ._config import get_run_validators, set_run_validators
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
from ._make import (
@@ -31,7 +32,7 @@ ib = attr = attrib
dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
-class AttrsInstance:
+class AttrsInstance(Protocol):
pass
@@ -90,8 +91,9 @@ def _make_getattr(mod_name: str) -> Callable:
"__email__": "",
"__license__": "license",
}
- if name not in dunder_to_metadata.keys():
- raise AttributeError(f"module {mod_name} has no attribute {name}")
+ if name not in dunder_to_metadata:
+ msg = f"module {mod_name} has no attribute {name}"
+ raise AttributeError(msg)
import sys
import warnings
@@ -101,7 +103,7 @@ def _make_getattr(mod_name: str) -> Callable:
else:
from importlib.metadata import metadata
- if name != "__version_info__":
+ if name not in ("__version__", "__version_info__"):
warnings.warn(
f"Accessing {mod_name}.{name} is deprecated and will be "
"removed in a future release. Use importlib.metadata directly "
@@ -113,15 +115,15 @@ def _make_getattr(mod_name: str) -> Callable:
meta = metadata("attrs")
if name == "__license__":
return "MIT"
- elif name == "__copyright__":
+ if name == "__copyright__":
return "Copyright (c) 2015 Hynek Schlawack"
- elif name in ("__uri__", "__url__"):
+ if name in ("__uri__", "__url__"):
return meta["Project-URL"].split(" ", 1)[-1]
- elif name == "__version_info__":
+ if name == "__version_info__":
return VersionInfo._from_version_string(meta["version"])
- elif name == "__author__":
+ if name == "__author__":
return meta["Author-email"].rsplit(" ", 1)[0]
- elif name == "__email__":
+ if name == "__email__":
return meta["Author-email"].rsplit("<", 1)[1][:-1]
return meta[dunder_to_metadata[name]]
diff --git a/contrib/python/attrs/py3/attr/_cmp.py b/contrib/python/attrs/py3/attr/_cmp.py
index d9cbe22cde..a4a35e08fc 100644
--- a/contrib/python/attrs/py3/attr/_cmp.py
+++ b/contrib/python/attrs/py3/attr/_cmp.py
@@ -92,10 +92,8 @@ def cmp_using(
if not has_eq_function:
# functools.total_ordering requires __eq__ to be defined,
# so raise early error here to keep a nice stack.
- raise ValueError(
- "eq must be define is order to complete ordering from "
- "lt, le, gt, ge."
- )
+ msg = "eq must be define is order to complete ordering from lt, le, gt, ge."
+ raise ValueError(msg)
type_ = functools.total_ordering(type_)
return type_
@@ -142,10 +140,7 @@ def _is_comparable_to(self, other):
"""
Check whether `other` is comparable to `self`.
"""
- for func in self._requirements:
- if not func(self, other):
- return False
- return True
+ return all(func(self, other) for func in self._requirements)
def _check_same_type(self, other):
diff --git a/contrib/python/attrs/py3/attr/_compat.py b/contrib/python/attrs/py3/attr/_compat.py
index c3bf5e33ba..46b05ca453 100644
--- a/contrib/python/attrs/py3/attr/_compat.py
+++ b/contrib/python/attrs/py3/attr/_compat.py
@@ -1,31 +1,28 @@
# SPDX-License-Identifier: MIT
-
import inspect
import platform
import sys
import threading
-import types
-import warnings
-from collections.abc import Mapping, Sequence # noqa
+from collections.abc import Mapping, Sequence # noqa: F401
from typing import _GenericAlias
PYPY = platform.python_implementation() == "PyPy"
+PY_3_8_PLUS = sys.version_info[:2] >= (3, 8)
PY_3_9_PLUS = sys.version_info[:2] >= (3, 9)
PY310 = sys.version_info[:2] >= (3, 10)
PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
-def just_warn(*args, **kw):
- warnings.warn(
- "Running interpreter doesn't sufficiently support code object "
- "introspection. Some features like bare super() or accessing "
- "__class__ will not work with slotted classes.",
- RuntimeWarning,
- stacklevel=2,
- )
+if sys.version_info < (3, 8):
+ try:
+ from typing_extensions import Protocol
+ except ImportError: # pragma: no cover
+ Protocol = object
+else:
+ from typing import Protocol # noqa: F401
class _AnnotationExtractor:
@@ -68,101 +65,6 @@ class _AnnotationExtractor:
return None
-def make_set_closure_cell():
- """Return a function of two arguments (cell, value) which sets
- the value stored in the closure cell `cell` to `value`.
- """
- # pypy makes this easy. (It also supports the logic below, but
- # why not do the easy/fast thing?)
- if PYPY:
-
- def set_closure_cell(cell, value):
- cell.__setstate__((value,))
-
- return set_closure_cell
-
- # Otherwise gotta do it the hard way.
-
- try:
- if sys.version_info >= (3, 8):
-
- def set_closure_cell(cell, value):
- cell.cell_contents = value
-
- else:
- # Create a function that will set its first cellvar to `value`.
- def set_first_cellvar_to(value):
- x = value
- return
-
- # This function will be eliminated as dead code, but
- # not before its reference to `x` forces `x` to be
- # represented as a closure cell rather than a local.
- def force_x_to_be_a_cell(): # pragma: no cover
- return x
-
- # Extract the code object and make sure our assumptions about
- # the closure behavior are correct.
- co = set_first_cellvar_to.__code__
- if co.co_cellvars != ("x",) or co.co_freevars != ():
- raise AssertionError # pragma: no cover
-
- # Convert this code object to a code object that sets the
- # function's first _freevar_ (not cellvar) to the argument.
- args = [co.co_argcount]
- args.append(co.co_kwonlyargcount)
- args.extend(
- [
- co.co_nlocals,
- co.co_stacksize,
- co.co_flags,
- co.co_code,
- co.co_consts,
- co.co_names,
- co.co_varnames,
- co.co_filename,
- co.co_name,
- co.co_firstlineno,
- co.co_lnotab,
- # These two arguments are reversed:
- co.co_cellvars,
- co.co_freevars,
- ]
- )
- set_first_freevar_code = types.CodeType(*args)
-
- def set_closure_cell(cell, value):
- # Create a function using the set_first_freevar_code,
- # whose first closure cell is `cell`. Calling it will
- # change the value of that cell.
- setter = types.FunctionType(
- set_first_freevar_code, {}, "setter", (), (cell,)
- )
- # And call it to set the cell.
- setter(value)
-
- # Make sure it works on this interpreter:
- def make_func_with_cell():
- x = None
-
- def func():
- return x # pragma: no cover
-
- return func
-
- cell = make_func_with_cell().__closure__[0]
- set_closure_cell(cell, 100)
- if cell.cell_contents != 100:
- raise AssertionError # pragma: no cover
-
- except Exception:
- return just_warn
- else:
- return set_closure_cell
-
-
-set_closure_cell = make_set_closure_cell()
-
# Thread-local global to track attrs instances which are already being repr'd.
# This is needed because there is no other (thread-safe) way to pass info
# about the instances that are already being repr'd through the call stack
diff --git a/contrib/python/attrs/py3/attr/_config.py b/contrib/python/attrs/py3/attr/_config.py
index 96d4200773..9c245b1461 100644
--- a/contrib/python/attrs/py3/attr/_config.py
+++ b/contrib/python/attrs/py3/attr/_config.py
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: MIT
-
__all__ = ["set_run_validators", "get_run_validators"]
_run_validators = True
@@ -15,7 +14,8 @@ def set_run_validators(run):
instead.
"""
if not isinstance(run, bool):
- raise TypeError("'run' must be bool.")
+ msg = "'run' must be bool."
+ raise TypeError(msg)
global _run_validators
_run_validators = run
diff --git a/contrib/python/attrs/py3/attr/_funcs.py b/contrib/python/attrs/py3/attr/_funcs.py
index 7f5d9610f3..a888991d98 100644
--- a/contrib/python/attrs/py3/attr/_funcs.py
+++ b/contrib/python/attrs/py3/attr/_funcs.py
@@ -72,19 +72,25 @@ def asdict(
)
elif isinstance(v, (tuple, list, set, frozenset)):
cf = v.__class__ if retain_collection_types is True else list
- rv[a.name] = cf(
- [
- _asdict_anything(
- i,
- is_key=False,
- filter=filter,
- dict_factory=dict_factory,
- retain_collection_types=retain_collection_types,
- value_serializer=value_serializer,
- )
- for i in v
- ]
- )
+ items = [
+ _asdict_anything(
+ i,
+ is_key=False,
+ filter=filter,
+ dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ )
+ for i in v
+ ]
+ try:
+ rv[a.name] = cf(items)
+ except TypeError:
+ if not issubclass(cf, tuple):
+ raise
+ # Workaround for TypeError: cf.__new__() missing 1 required
+ # positional argument (which appears, for a namedturle)
+ rv[a.name] = cf(*items)
elif isinstance(v, dict):
df = dict_factory
rv[a.name] = df(
@@ -241,22 +247,26 @@ def astuple(
)
elif isinstance(v, (tuple, list, set, frozenset)):
cf = v.__class__ if retain is True else list
- rv.append(
- cf(
- [
- astuple(
- j,
- recurse=True,
- filter=filter,
- tuple_factory=tuple_factory,
- retain_collection_types=retain,
- )
- if has(j.__class__)
- else j
- for j in v
- ]
+ items = [
+ astuple(
+ j,
+ recurse=True,
+ filter=filter,
+ tuple_factory=tuple_factory,
+ retain_collection_types=retain,
)
- )
+ if has(j.__class__)
+ else j
+ for j in v
+ ]
+ try:
+ rv.append(cf(items))
+ except TypeError:
+ if not issubclass(cf, tuple):
+ raise
+ # Workaround for TypeError: cf.__new__() missing 1 required
+ # positional argument (which appears, for a namedturle)
+ rv.append(cf(*items))
elif isinstance(v, dict):
df = v.__class__ if retain is True else dict
rv.append(
@@ -344,9 +354,8 @@ def assoc(inst, **changes):
for k, v in changes.items():
a = getattr(attrs, k, NOTHING)
if a is NOTHING:
- raise AttrsAttributeNotFoundError(
- f"{k} is not an attrs attribute on {new.__class__}."
- )
+ msg = f"{k} is not an attrs attribute on {new.__class__}."
+ raise AttrsAttributeNotFoundError(msg)
_obj_setattr(new, k, v)
return new
@@ -379,17 +388,14 @@ def evolve(*args, **changes):
try:
(inst,) = args
except ValueError:
- raise TypeError(
- f"evolve() takes 1 positional argument, but {len(args)} "
- "were given"
- ) from None
+ msg = f"evolve() takes 1 positional argument, but {len(args)} were given"
+ raise TypeError(msg) from None
else:
try:
inst = changes.pop("inst")
except KeyError:
- raise TypeError(
- "evolve() missing 1 required positional argument: 'inst'"
- ) from None
+ msg = "evolve() missing 1 required positional argument: 'inst'"
+ raise TypeError(msg) from None
import warnings
diff --git a/contrib/python/attrs/py3/attr/_make.py b/contrib/python/attrs/py3/attr/_make.py
index d72f738eec..10b4eca779 100644
--- a/contrib/python/attrs/py3/attr/_make.py
+++ b/contrib/python/attrs/py3/attr/_make.py
@@ -1,7 +1,11 @@
# SPDX-License-Identifier: MIT
+import contextlib
import copy
import enum
+import functools
+import inspect
+import itertools
import linecache
import sys
import types
@@ -14,9 +18,9 @@ from operator import itemgetter
from . import _compat, _config, setters
from ._compat import (
PY310,
+ PY_3_8_PLUS,
_AnnotationExtractor,
get_generic_base,
- set_closure_cell,
)
from .exceptions import (
DefaultAlreadySetError,
@@ -87,7 +91,7 @@ class _CacheHashWrapper(int):
See GH #613 for more details.
"""
- def __reduce__(self, _none_constructor=type(None), _args=()):
+ def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008
return _none_constructor, _args
@@ -113,8 +117,8 @@ def attrib(
.. warning::
- Does *not* do anything unless the class is also decorated with
- `attr.s` / `attrs.define` / et cetera!
+ Does *not* do anything unless the class is also decorated with `attr.s`
+ / `attrs.define` / and so on!
Please consider using `attrs.field` in new code (``attr.ib`` will *never*
go away, though).
@@ -128,12 +132,12 @@ def attrib(
or dicts).
If a default is not set (or set manually to `attrs.NOTHING`), a value
- *must* be supplied when instantiating; otherwise a `TypeError`
- will be raised.
+ *must* be supplied when instantiating; otherwise a `TypeError` will be
+ raised.
The default can also be set using decorator notation as shown below.
- :type default: Any value
+ .. seealso:: `defaults`
:param callable factory: Syntactic sugar for
``default=attr.Factory(factory)``.
@@ -146,69 +150,80 @@ def attrib(
The return value is *not* inspected so the validator has to throw an
exception itself.
- If a `list` is passed, its items are treated as validators and must
- all pass.
+ If a `list` is passed, its items are treated as validators and must all
+ pass.
Validators can be globally disabled and re-enabled using
`attrs.validators.get_disabled` / `attrs.validators.set_disabled`.
The validator can also be set using decorator notation as shown below.
+ .. seealso:: :ref:`validators`
+
:type validator: `callable` or a `list` of `callable`\\ s.
- :param repr: Include this attribute in the generated ``__repr__``
- method. If ``True``, include the attribute; if ``False``, omit it. By
- default, the built-in ``repr()`` function is used. To override how the
- attribute value is formatted, pass a ``callable`` that takes a single
- value and returns a string. Note that the resulting string is used
- as-is, i.e. it will be used directly *instead* of calling ``repr()``
- (the default).
+ :param repr: Include this attribute in the generated ``__repr__`` method.
+ If ``True``, include the attribute; if ``False``, omit it. By default,
+ the built-in ``repr()`` function is used. To override how the attribute
+ value is formatted, pass a ``callable`` that takes a single value and
+ returns a string. Note that the resulting string is used as-is, i.e. it
+ will be used directly *instead* of calling ``repr()`` (the default).
:type repr: a `bool` or a `callable` to use a custom function.
- :param eq: If ``True`` (default), include this attribute in the
- generated ``__eq__`` and ``__ne__`` methods that check two instances
- for equality. To override how the attribute value is compared,
- pass a ``callable`` that takes a single value and returns the value
- to be compared.
+ :param eq: If ``True`` (default), include this attribute in the generated
+ ``__eq__`` and ``__ne__`` methods that check two instances for
+ equality. To override how the attribute value is compared, pass a
+ ``callable`` that takes a single value and returns the value to be
+ compared.
+
+ .. seealso:: `comparison`
:type eq: a `bool` or a `callable`.
:param order: If ``True`` (default), include this attributes in the
- generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods.
- To override how the attribute value is ordered,
- pass a ``callable`` that takes a single value and returns the value
- to be ordered.
+ generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To
+ override how the attribute value is ordered, pass a ``callable`` that
+ takes a single value and returns the value to be ordered.
+
+ .. seealso:: `comparison`
:type order: a `bool` or a `callable`.
:param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the
same value. Must not be mixed with *eq* or *order*.
+
+ .. seealso:: `comparison`
:type cmp: a `bool` or a `callable`.
- :param Optional[bool] hash: Include this attribute in the generated
+ :param bool | None hash: Include this attribute in the generated
``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This
is the correct behavior according the Python spec. Setting this value
to anything else than ``None`` is *discouraged*.
+
+ .. seealso:: `hashing`
:param bool init: Include this attribute in the generated ``__init__``
method. It is possible to set this to ``False`` and set a default
value. In that case this attributed is unconditionally initialized
with the specified default value or factory.
- :param callable converter: `callable` that is called by
- *attrs*-generated ``__init__`` methods to convert attribute's value
- to the desired format. It is given the passed-in value, and the
- returned value will be used as the new value of the attribute. The
- value is converted before being passed to the validator, if any.
- :param metadata: An arbitrary mapping, to be used by third-party
- components. See `extending-metadata`.
+
+ .. seealso:: `init`
+ :param callable converter: `callable` that is called by *attrs*-generated
+ ``__init__`` methods to convert attribute's value to the desired
+ format. It is given the passed-in value, and the returned value will
+ be used as the new value of the attribute. The value is converted
+ before being passed to the validator, if any.
+
+ .. seealso:: :ref:`converters`
+ :param dict | None metadata: An arbitrary mapping, to be used by
+ third-party components. See `extending-metadata`.
:param type: The type of the attribute. Nowadays, the preferred method to
- specify the type is using a variable annotation (see :pep:`526`).
- This argument is provided for backward compatibility.
- Regardless of the approach used, the type will be stored on
- ``Attribute.type``.
+ specify the type is using a variable annotation (see :pep:`526`). This
+ argument is provided for backward compatibility. Regardless of the
+ approach used, the type will be stored on ``Attribute.type``.
Please note that *attrs* doesn't do anything with this metadata by
- itself. You can use it as part of your own code or for
- `static type checking <types>`.
- :param kw_only: Make this attribute keyword-only in the generated
+ itself. You can use it as part of your own code or for `static type
+ checking <types>`.
+ :param bool kw_only: Make this attribute keyword-only in the generated
``__init__`` (if ``init`` is ``False``, this parameter is ignored).
:param on_setattr: Allows to overwrite the *on_setattr* setting from
`attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used.
@@ -216,7 +231,7 @@ def attrib(
attribute -- regardless of the setting in `attr.s`.
:type on_setattr: `callable`, or a list of callables, or `None`, or
`attrs.setters.NO_OP`
- :param Optional[str] alias: Override this attribute's parameter name in the
+ :param str | None alias: Override this attribute's parameter name in the
generated ``__init__`` method. If left `None`, default to ``name``
stripped of leading underscores. See `private-attributes`.
@@ -248,18 +263,18 @@ def attrib(
)
if hash is not None and hash is not True and hash is not False:
- raise TypeError(
- "Invalid value for hash. Must be True, False, or None."
- )
+ msg = "Invalid value for hash. Must be True, False, or None."
+ raise TypeError(msg)
if factory is not None:
if default is not NOTHING:
- raise ValueError(
- "The `default` and `factory` arguments are mutually "
- "exclusive."
+ msg = (
+ "The `default` and `factory` arguments are mutually exclusive."
)
+ raise ValueError(msg)
if not callable(factory):
- raise ValueError("The `factory` argument must be a callable.")
+ msg = "The `factory` argument must be a callable."
+ raise ValueError(msg)
default = Factory(factory)
if metadata is None:
@@ -323,9 +338,9 @@ def _make_method(name, script, filename, globs):
old_val = linecache.cache.setdefault(filename, linecache_tuple)
if old_val == linecache_tuple:
break
- else:
- filename = f"{base_filename[:-1]}-{count}>"
- count += 1
+
+ filename = f"{base_filename[:-1]}-{count}>"
+ count += 1
_compile_and_eval(script, globs, locs, filename)
@@ -430,7 +445,7 @@ def _collect_base_attrs(cls, taken_attr_names):
if a.inherited or a.name in taken_attr_names:
continue
- a = a.evolve(inherited=True)
+ a = a.evolve(inherited=True) # noqa: PLW2901
base_attrs.append(a)
base_attr_map[a.name] = base_cls
@@ -468,7 +483,7 @@ def _collect_base_attrs_broken(cls, taken_attr_names):
if a.name in taken_attr_names:
continue
- a = a.evolve(inherited=True)
+ a = a.evolve(inherited=True) # noqa: PLW2901
taken_attr_names.add(a.name)
base_attrs.append(a)
base_attr_map[a.name] = base_cls
@@ -493,7 +508,7 @@ def _transform_attrs(
anns = _get_annotations(cls)
if these is not None:
- ca_list = [(name, ca) for name, ca in these.items()]
+ ca_list = list(these.items())
elif auto_attribs is True:
ca_names = {
name
@@ -509,10 +524,7 @@ def _transform_attrs(
a = cd.get(attr_name, NOTHING)
if not isinstance(a, _CountingAttr):
- if a is NOTHING:
- a = attrib()
- else:
- a = attrib(default=a)
+ a = attrib() if a is NOTHING else attrib(default=a)
ca_list.append((attr_name, a))
unannotated = ca_names - annot_names
@@ -563,10 +575,8 @@ def _transform_attrs(
had_default = False
for a in (a for a in attrs if a.init is not False and a.kw_only is False):
if had_default is True and a.default is NOTHING:
- raise ValueError(
- "No mandatory attributes allowed after an attribute with a "
- f"default value or factory. Attribute in question: {a!r}"
- )
+ msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}"
+ raise ValueError(msg)
if had_default is False and a.default is not NOTHING:
had_default = True
@@ -590,6 +600,62 @@ def _transform_attrs(
return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map))
+def _make_cached_property_getattr(
+ cached_properties,
+ original_getattr,
+ cls,
+):
+ lines = [
+ # Wrapped to get `__class__` into closure cell for super()
+ # (It will be replaced with the newly constructed class after construction).
+ "def wrapper():",
+ " __class__ = _cls",
+ " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):",
+ " func = cached_properties.get(item)",
+ " if func is not None:",
+ " result = func(self)",
+ " _setter = _cached_setattr_get(self)",
+ " _setter(item, result)",
+ " return result",
+ ]
+ if original_getattr is not None:
+ lines.append(
+ " return original_getattr(self, item)",
+ )
+ else:
+ lines.extend(
+ [
+ " if hasattr(super(), '__getattr__'):",
+ " return super().__getattr__(item)",
+ " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"",
+ " raise AttributeError(original_error)",
+ ]
+ )
+
+ lines.extend(
+ [
+ " return __getattr__",
+ "__getattr__ = wrapper()",
+ ]
+ )
+
+ unique_filename = _generate_unique_filename(cls, "getattr")
+
+ glob = {
+ "cached_properties": cached_properties,
+ "_cached_setattr_get": _obj_setattr.__get__,
+ "_cls": cls,
+ "original_getattr": original_getattr,
+ }
+
+ return _make_method(
+ "__getattr__",
+ "\n".join(lines),
+ unique_filename,
+ glob,
+ )
+
+
def _frozen_setattrs(self, name, value):
"""
Attached to frozen classes as __setattr__.
@@ -628,6 +694,7 @@ class _ClassBuilder:
"_delete_attribs",
"_frozen",
"_has_pre_init",
+ "_pre_init_has_args",
"_has_post_init",
"_is_exc",
"_on_setattr",
@@ -674,6 +741,13 @@ class _ClassBuilder:
self._weakref_slot = weakref_slot
self._cache_hash = cache_hash
self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
+ self._pre_init_has_args = False
+ if self._has_pre_init:
+ # Check if the pre init method has more arguments than just `self`
+ # We want to pass arguments if pre init expects arguments
+ pre_init_func = cls.__attrs_pre_init__
+ pre_init_signature = inspect.signature(pre_init_func)
+ self._pre_init_has_args = len(pre_init_signature.parameters) > 1
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
self._delete_attribs = not bool(these)
self._is_exc = is_exc
@@ -768,13 +842,11 @@ class _ClassBuilder:
name not in base_names
and getattr(cls, name, _sentinel) is not _sentinel
):
- try:
+ # An AttributeError can happen if a base class defines a
+ # class variable and we want to set an attribute with the
+ # same name by using only a type annotation.
+ with contextlib.suppress(AttributeError):
delattr(cls, name)
- except AttributeError:
- # This can happen if a base class defines a class
- # variable and we want to set an attribute with the
- # same name by using only a type annotation.
- pass
# Attach our dunder methods.
for name, value in self._cls_dict.items():
@@ -799,7 +871,7 @@ class _ClassBuilder:
cd = {
k: v
for k, v in self._cls_dict.items()
- if k not in tuple(self._attr_names) + ("__dict__", "__weakref__")
+ if k not in (*tuple(self._attr_names), "__dict__", "__weakref__")
}
# If our class doesn't have its own implementation of __setattr__
@@ -821,7 +893,7 @@ class _ClassBuilder:
# Traverse the MRO to collect existing slots
# and check for an existing __weakref__.
- existing_slots = dict()
+ existing_slots = {}
weakref_inherited = False
for base_cls in self._cls.__mro__[1:-1]:
if base_cls.__dict__.get("__weakref__", None) is not None:
@@ -844,9 +916,46 @@ class _ClassBuilder:
):
names += ("__weakref__",)
+ if PY_3_8_PLUS:
+ cached_properties = {
+ name: cached_property.func
+ for name, cached_property in cd.items()
+ if isinstance(cached_property, functools.cached_property)
+ }
+ else:
+ # `functools.cached_property` was introduced in 3.8.
+ # So can't be used before this.
+ cached_properties = {}
+
+ # Collect methods with a `__class__` reference that are shadowed in the new class.
+ # To know to update them.
+ additional_closure_functions_to_update = []
+ if cached_properties:
+ # Add cached properties to names for slotting.
+ names += tuple(cached_properties.keys())
+
+ for name in cached_properties:
+ # Clear out function from class to avoid clashing.
+ del cd[name]
+
+ class_annotations = _get_annotations(self._cls)
+ for name, func in cached_properties.items():
+ annotation = inspect.signature(func).return_annotation
+ if annotation is not inspect.Parameter.empty:
+ class_annotations[name] = annotation
+
+ original_getattr = cd.get("__getattr__")
+ if original_getattr is not None:
+ additional_closure_functions_to_update.append(original_getattr)
+
+ cd["__getattr__"] = _make_cached_property_getattr(
+ cached_properties, original_getattr, self._cls
+ )
+
# We only add the names of attributes that aren't inherited.
# Setting __slots__ to inherited attributes wastes memory.
slot_names = [name for name in names if name not in base_names]
+
# There are slots for attributes from current class
# that are defined in parent classes.
# As their descriptors may be overridden by a child class,
@@ -860,6 +969,7 @@ class _ClassBuilder:
cd.update(reused_slots)
if self._cache_hash:
slot_names.append(_hash_cache_field)
+
cd["__slots__"] = tuple(slot_names)
cd["__qualname__"] = self._cls.__qualname__
@@ -873,7 +983,9 @@ class _ClassBuilder:
# compiler will bake a reference to the class in the method itself
# as `method.__closure__`. Since we replace the class with a
# clone, we rewrite these references so it keeps working.
- for item in cls.__dict__.values():
+ for item in itertools.chain(
+ cls.__dict__.values(), additional_closure_functions_to_update
+ ):
if isinstance(item, (classmethod, staticmethod)):
# Class- and staticmethods hide their functions inside.
# These might need to be rewritten as well.
@@ -890,12 +1002,12 @@ class _ClassBuilder:
for cell in closure_cells:
try:
match = cell.cell_contents is self._cls
- except ValueError: # ValueError: Cell is empty
+ except ValueError: # noqa: PERF203
+ # ValueError: Cell is empty
pass
else:
if match:
- set_closure_cell(cell, cls)
-
+ cell.cell_contents = cls
return cls
def add_repr(self, ns):
@@ -907,9 +1019,8 @@ class _ClassBuilder:
def add_str(self):
repr = self._cls_dict.get("__repr__")
if repr is None:
- raise ValueError(
- "__str__ can only be generated if a __repr__ exists."
- )
+ msg = "__str__ can only be generated if a __repr__ exists."
+ raise ValueError(msg)
def __str__(self):
return self.__repr__()
@@ -980,6 +1091,7 @@ class _ClassBuilder:
self._cls,
self._attrs,
self._has_pre_init,
+ self._pre_init_has_args,
self._has_post_init,
self._frozen,
self._slots,
@@ -1006,6 +1118,7 @@ class _ClassBuilder:
self._cls,
self._attrs,
self._has_pre_init,
+ self._pre_init_has_args,
self._has_post_init,
self._frozen,
self._slots,
@@ -1054,9 +1167,8 @@ class _ClassBuilder:
if self._has_custom_setattr:
# We need to write a __setattr__ but there already is one!
- raise ValueError(
- "Can't combine custom __setattr__ with on_setattr hooks."
- )
+ msg = "Can't combine custom __setattr__ with on_setattr hooks."
+ raise ValueError(msg)
# docstring comes from _add_method_dunders
def __setattr__(self, name, val):
@@ -1079,25 +1191,17 @@ class _ClassBuilder:
"""
Add __module__ and __qualname__ to a *method* if possible.
"""
- try:
+ with contextlib.suppress(AttributeError):
method.__module__ = self._cls.__module__
- except AttributeError:
- pass
- try:
- method.__qualname__ = ".".join(
- (self._cls.__qualname__, method.__name__)
- )
- except AttributeError:
- pass
+ with contextlib.suppress(AttributeError):
+ method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}"
- try:
+ with contextlib.suppress(AttributeError):
method.__doc__ = (
"Method generated by attrs for class "
f"{self._cls.__qualname__}."
)
- except AttributeError:
- pass
return method
@@ -1108,7 +1212,8 @@ def _determine_attrs_eq_order(cmp, eq, order, default_eq):
values of eq and order. If *eq* is None, set it to *default_eq*.
"""
if cmp is not None and any((eq is not None, order is not None)):
- raise ValueError("Don't mix `cmp` with `eq' and `order`.")
+ msg = "Don't mix `cmp` with `eq' and `order`."
+ raise ValueError(msg)
# cmp takes precedence due to bw-compatibility.
if cmp is not None:
@@ -1123,7 +1228,8 @@ def _determine_attrs_eq_order(cmp, eq, order, default_eq):
order = eq
if eq is False and order is True:
- raise ValueError("`order` can only be True if `eq` is True too.")
+ msg = "`order` can only be True if `eq` is True too."
+ raise ValueError(msg)
return eq, order
@@ -1134,7 +1240,8 @@ def _determine_attrib_eq_order(cmp, eq, order, default_eq):
values of eq and order. If *eq* is None, set it to *default_eq*.
"""
if cmp is not None and any((eq is not None, order is not None)):
- raise ValueError("Don't mix `cmp` with `eq' and `order`.")
+ msg = "Don't mix `cmp` with `eq' and `order`."
+ raise ValueError(msg)
def decide_callable_or_boolean(value):
"""
@@ -1164,7 +1271,8 @@ def _determine_attrib_eq_order(cmp, eq, order, default_eq):
order, order_key = decide_callable_or_boolean(order)
if eq is False and order is True:
- raise ValueError("`order` can only be True if `eq` is True too.")
+ msg = "`order` can only be True if `eq` is True too."
+ raise ValueError(msg)
return eq, eq_key, order, order_key
@@ -1228,8 +1336,8 @@ def attrs(
Please consider using `attrs.define` / `attrs.frozen` in new code
(``attr.s`` will *never* go away, though).
- :param these: A dictionary of name to `attr.ib` mappings. This is
- useful to avoid the definition of your attributes within the class body
+ :param these: A dictionary of name to `attr.ib` mappings. This is useful
+ to avoid the definition of your attributes within the class body
because you can't (e.g. if you want to add ``__repr__`` methods to
Django models) or don't want to.
@@ -1249,11 +1357,11 @@ def attrs(
arguments is implemented in the *current* class (i.e. it is *not*
inherited from some base class).
- So for example by implementing ``__eq__`` on a class yourself,
- *attrs* will deduce ``eq=False`` and will create *neither*
- ``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible
- ``__ne__`` by default, so it *should* be enough to only implement
- ``__eq__`` in most cases).
+ So for example by implementing ``__eq__`` on a class yourself, *attrs*
+ will deduce ``eq=False`` and will create *neither* ``__eq__`` *nor*
+ ``__ne__`` (but Python classes come with a sensible ``__ne__`` by
+ default, so it *should* be enough to only implement ``__eq__`` in most
+ cases).
.. warning::
@@ -1263,26 +1371,31 @@ def attrs(
way is to use the `functools.total_ordering` decorator.
- Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*,
- *cmp*, or *hash* overrides whatever *auto_detect* would determine.
+ Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, *cmp*,
+ or *hash* overrides whatever *auto_detect* would determine.
:param bool repr: Create a ``__repr__`` method with a human readable
representation of *attrs* attributes..
:param bool str: Create a ``__str__`` method that is identical to
- ``__repr__``. This is usually not necessary except for
- `Exception`\ s.
- :param Optional[bool] eq: If ``True`` or ``None`` (default), add ``__eq__``
+ ``__repr__``. This is usually not necessary except for `Exception`\ s.
+ :param bool | None eq: If ``True`` or ``None`` (default), add ``__eq__``
and ``__ne__`` methods that check two instances for equality.
They compare the instances as if they were tuples of their *attrs*
attributes if and only if the types of both classes are *identical*!
- :param Optional[bool] order: If ``True``, add ``__lt__``, ``__le__``,
+
+ .. seealso:: `comparison`
+ :param bool | None order: If ``True``, add ``__lt__``, ``__le__``,
``__gt__``, and ``__ge__`` methods that behave like *eq* above and
allow instances to be ordered. If ``None`` (default) mirror value of
*eq*.
- :param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq*
- and *order* to the same value. Must not be mixed with *eq* or *order*.
- :param Optional[bool] unsafe_hash: If ``None`` (default), the ``__hash__``
+
+ .. seealso:: `comparison`
+ :param bool | None cmp: Setting *cmp* is equivalent to setting *eq* and
+ *order* to the same value. Must not be mixed with *eq* or *order*.
+
+ .. seealso:: `comparison`
+ :param bool | None unsafe_hash: If ``None`` (default), the ``__hash__``
method is generated according how *eq* and *frozen* are set.
1. If *both* are True, *attrs* will generate a ``__hash__`` for you.
@@ -1292,28 +1405,34 @@ def attrs(
``__hash__`` method of the base class will be used (if base class is
``object``, this means it will fall back to id-based hashing.).
- Although not recommended, you can decide for yourself and force
- *attrs* to create one (e.g. if the class is immutable even though you
- didn't freeze it programmatically) by passing ``True`` or not. Both of
- these cases are rather special and should be used carefully.
+ Although not recommended, you can decide for yourself and force *attrs*
+ to create one (e.g. if the class is immutable even though you didn't
+ freeze it programmatically) by passing ``True`` or not. Both of these
+ cases are rather special and should be used carefully.
- See our documentation on `hashing`, Python's documentation on
- `object.__hash__`, and the `GitHub issue that led to the default \
- behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more
- details.
- :param Optional[bool] hash: Alias for *unsafe_hash*. *unsafe_hash* takes
+ .. seealso::
+
+ - Our documentation on `hashing`,
+ - Python's documentation on `object.__hash__`,
+ - and the `GitHub issue that led to the default \
+ behavior <https://github.com/python-attrs/attrs/issues/136>`_ for
+ more details.
+
+ :param bool | None hash: Alias for *unsafe_hash*. *unsafe_hash* takes
precedence.
- :param bool init: Create a ``__init__`` method that initializes the
- *attrs* attributes. Leading underscores are stripped for the argument
- name. If a ``__attrs_pre_init__`` method exists on the class, it will
- be called before the class is initialized. If a ``__attrs_post_init__``
- method exists on the class, it will be called after the class is fully
+ :param bool init: Create a ``__init__`` method that initializes the *attrs*
+ attributes. Leading underscores are stripped for the argument name. If
+ a ``__attrs_pre_init__`` method exists on the class, it will be called
+ before the class is initialized. If a ``__attrs_post_init__`` method
+ exists on the class, it will be called after the class is fully
initialized.
- If ``init`` is ``False``, an ``__attrs_init__`` method will be
- injected instead. This allows you to define a custom ``__init__``
- method that can do pre-init work such as ``super().__init__()``,
- and then call ``__attrs_init__()`` and ``__attrs_post_init__()``.
+ If ``init`` is ``False``, an ``__attrs_init__`` method will be injected
+ instead. This allows you to define a custom ``__init__`` method that
+ can do pre-init work such as ``super().__init__()``, and then call
+ ``__attrs_init__()`` and ``__attrs_post_init__()``.
+
+ .. seealso:: `init`
:param bool slots: Create a :term:`slotted class <slotted classes>` that's
more memory-efficient. Slotted classes are generally superior to the
default dict classes, but have some gotchas you should know about, so
@@ -1335,8 +1454,8 @@ def attrs(
4. If a class is frozen, you cannot modify ``self`` in
``__attrs_post_init__`` or a self-written ``__init__``. You can
- circumvent that limitation by using
- ``object.__setattr__(self, "attribute_name", value)``.
+ circumvent that limitation by using ``object.__setattr__(self,
+ "attribute_name", value)``.
5. Subclasses of a frozen class are frozen too.
@@ -1345,11 +1464,11 @@ def attrs(
:param bool auto_attribs: If ``True``, collect :pep:`526`-annotated
attributes from the class body.
- In this case, you **must** annotate every field. If *attrs*
- encounters a field that is set to an `attr.ib` but lacks a type
- annotation, an `attr.exceptions.UnannotatedAttributeError` is
- raised. Use ``field_name: typing.Any = attr.ib(...)`` if you don't
- want to set a type.
+ In this case, you **must** annotate every field. If *attrs* encounters
+ a field that is set to an `attr.ib` but lacks a type annotation, an
+ `attr.exceptions.UnannotatedAttributeError` is raised. Use
+ ``field_name: typing.Any = attr.ib(...)`` if you don't want to set a
+ type.
If you assign a value to those attributes (e.g. ``x: int = 42``), that
value becomes the default value like if it were passed using
@@ -1368,20 +1487,18 @@ def attrs(
These errors can be quite confusing and probably the most common bug
report on our bug tracker.
- :param bool kw_only: Make all attributes keyword-only
- in the generated ``__init__`` (if ``init`` is ``False``, this
- parameter is ignored).
- :param bool cache_hash: Ensure that the object's hash code is computed
- only once and stored on the object. If this is set to ``True``,
- hashing must be either explicitly or implicitly enabled for this
- class. If the hash code is cached, avoid any reassignments of
- fields involved in hash code computation or mutations of the objects
- those fields point to after object creation. If such changes occur,
- the behavior of the object's hash code is undefined.
- :param bool auto_exc: If the class subclasses `BaseException`
- (which implicitly includes any subclass of any exception), the
- following happens to behave like a well-behaved Python exceptions
- class:
+ :param bool kw_only: Make all attributes keyword-only in the generated
+ ``__init__`` (if ``init`` is ``False``, this parameter is ignored).
+ :param bool cache_hash: Ensure that the object's hash code is computed only
+ once and stored on the object. If this is set to ``True``, hashing
+ must be either explicitly or implicitly enabled for this class. If the
+ hash code is cached, avoid any reassignments of fields involved in hash
+ code computation or mutations of the objects those fields point to
+ after object creation. If such changes occur, the behavior of the
+ object's hash code is undefined.
+ :param bool auto_exc: If the class subclasses `BaseException` (which
+ implicitly includes any subclass of any exception), the following
+ happens to behave like a well-behaved Python exceptions class:
- the values for *eq*, *order*, and *hash* are ignored and the
instances compare and hash by the instance's ids (N.B. *attrs* will
@@ -1396,22 +1513,22 @@ def attrs(
incorrect in certain cases of multiple inheritance. It should be on by
default but is kept off for backward-compatibility.
- See issue `#428 <https://github.com/python-attrs/attrs/issues/428>`_ for
- more details.
+ .. seealso::
+ Issue `#428 <https://github.com/python-attrs/attrs/issues/428>`_
- :param Optional[bool] getstate_setstate:
+ :param bool | None getstate_setstate:
.. note::
This is usually only interesting for slotted classes and you should
probably just set *auto_detect* to `True`.
- If `True`, ``__getstate__`` and
- ``__setstate__`` are generated and attached to the class. This is
- necessary for slotted classes to be pickleable. If left `None`, it's
- `True` by default for slotted classes and ``False`` for dict classes.
+ If `True`, ``__getstate__`` and ``__setstate__`` are generated and
+ attached to the class. This is necessary for slotted classes to be
+ pickleable. If left `None`, it's `True` by default for slotted classes
+ and ``False`` for dict classes.
- If *auto_detect* is `True`, and *getstate_setstate* is left `None`,
- and **either** ``__getstate__`` or ``__setstate__`` is detected directly
- on the class (i.e. not inherited), it is set to `False` (this is usually
+ If *auto_detect* is `True`, and *getstate_setstate* is left `None`, and
+ **either** ``__getstate__`` or ``__setstate__`` is detected directly on
+ the class (i.e. not inherited), it is set to `False` (this is usually
what you want).
:param on_setattr: A callable that is run whenever the user attempts to set
@@ -1428,11 +1545,13 @@ def attrs(
:type on_setattr: `callable`, or a list of callables, or `None`, or
`attrs.setters.NO_OP`
- :param Optional[callable] field_transformer:
- A function that is called with the original class object and all
- fields right before *attrs* finalizes the class. You can use
- this, e.g., to automatically add converters or validators to
- fields based on their types. See `transform-fields` for more details.
+ :param callable | None field_transformer:
+ A function that is called with the original class object and all fields
+ right before *attrs* finalizes the class. You can use this, e.g., to
+ automatically add converters or validators to fields based on their
+ types.
+
+ .. seealso:: `transform-fields`
:param bool match_args:
If `True` (default), set ``__match_args__`` on the class to support
@@ -1494,7 +1613,8 @@ def attrs(
)
if has_own_setattr and is_frozen:
- raise ValueError("Can't freeze a class with a custom __setattr__.")
+ msg = "Can't freeze a class with a custom __setattr__."
+ raise ValueError(msg)
builder = _ClassBuilder(
cls,
@@ -1547,18 +1667,15 @@ def attrs(
if hash is not True and hash is not False and hash is not None:
# Can't use `hash in` because 1 == True for example.
- raise TypeError(
- "Invalid value for hash. Must be True, False, or None."
- )
- elif hash is False or (hash is None and eq is False) or is_exc:
+ msg = "Invalid value for hash. Must be True, False, or None."
+ raise TypeError(msg)
+
+ if hash is False or (hash is None and eq is False) or is_exc:
# Don't do anything. Should fall back to __object__'s __hash__
# which is by id.
if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " hashing must be either explicitly or implicitly "
- "enabled."
- )
+ msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
+ raise TypeError(msg)
elif hash is True or (
hash is None and eq is True and is_frozen is True
):
@@ -1567,11 +1684,8 @@ def attrs(
else:
# Raise TypeError on attempts to hash.
if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " hashing must be either explicitly or implicitly "
- "enabled."
- )
+ msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
+ raise TypeError(msg)
builder.make_unhashable()
if _determine_whether_to_implement(
@@ -1581,10 +1695,8 @@ def attrs(
else:
builder.add_attrs_init()
if cache_hash:
- raise TypeError(
- "Invalid value for cache_hash. To use hash caching,"
- " init must be True."
- )
+ msg = "Invalid value for cache_hash. To use hash caching, init must be True."
+ raise TypeError(msg)
if (
PY310
@@ -1599,8 +1711,8 @@ def attrs(
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
if maybe_cls is None:
return wrap
- else:
- return wrap(maybe_cls)
+
+ return wrap(maybe_cls)
_attrs = attrs
@@ -1648,10 +1760,7 @@ def _make_hash(cls, attrs, frozen, cache_hash):
else:
hash_def += ", *"
- hash_def += (
- ", _cache_wrapper="
- + "__import__('attr._make')._make._CacheHashWrapper):"
- )
+ hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):"
hash_func = "_cache_wrapper(" + hash_func
closing_braces += ")"
@@ -1760,7 +1869,7 @@ def _make_eq(cls, attrs):
lines.append(f" self.{a.name},")
others.append(f" other.{a.name},")
- lines += others + [" )"]
+ lines += [*others, " )"]
else:
lines.append(" return True")
@@ -1928,7 +2037,8 @@ def fields(cls):
generic_base = get_generic_base(cls)
if generic_base is None and not isinstance(cls, type):
- raise TypeError("Passed object must be a class.")
+ msg = "Passed object must be a class."
+ raise TypeError(msg)
attrs = getattr(cls, "__attrs_attrs__", None)
@@ -1941,7 +2051,8 @@ def fields(cls):
# efficient.
cls.__attrs_attrs__ = attrs
return attrs
- raise NotAnAttrsClassError(f"{cls!r} is not an attrs-decorated class.")
+ msg = f"{cls!r} is not an attrs-decorated class."
+ raise NotAnAttrsClassError(msg)
return attrs
@@ -1962,10 +2073,12 @@ def fields_dict(cls):
.. versionadded:: 18.1.0
"""
if not isinstance(cls, type):
- raise TypeError("Passed object must be a class.")
+ msg = "Passed object must be a class."
+ raise TypeError(msg)
attrs = getattr(cls, "__attrs_attrs__", None)
if attrs is None:
- raise NotAnAttrsClassError(f"{cls!r} is not an attrs-decorated class.")
+ msg = f"{cls!r} is not an attrs-decorated class."
+ raise NotAnAttrsClassError(msg)
return {a.name: a for a in attrs}
@@ -2001,6 +2114,7 @@ def _make_init(
cls,
attrs,
pre_init,
+ pre_init_has_args,
post_init,
frozen,
slots,
@@ -2015,7 +2129,8 @@ def _make_init(
)
if frozen and has_cls_on_setattr:
- raise ValueError("Frozen classes can't use on_setattr.")
+ msg = "Frozen classes can't use on_setattr."
+ raise ValueError(msg)
needs_cached_setattr = cache_hash or frozen
filtered_attrs = []
@@ -2029,7 +2144,8 @@ def _make_init(
if a.on_setattr is not None:
if frozen is True:
- raise ValueError("Frozen classes can't use on_setattr.")
+ msg = "Frozen classes can't use on_setattr."
+ raise ValueError(msg)
needs_cached_setattr = True
elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP:
@@ -2042,6 +2158,7 @@ def _make_init(
frozen,
slots,
pre_init,
+ pre_init_has_args,
post_init,
cache_hash,
base_attr_map,
@@ -2122,6 +2239,7 @@ def _attrs_to_init_script(
frozen,
slots,
pre_init,
+ pre_init_has_args,
post_init,
cache_hash,
base_attr_map,
@@ -2208,10 +2326,7 @@ def _attrs_to_init_script(
arg_name = a.alias
has_factory = isinstance(a.default, Factory)
- if has_factory and a.default.takes_self:
- maybe_self = "self"
- else:
- maybe_self = ""
+ maybe_self = "self" if has_factory and a.default.takes_self else ""
if a.init is False:
if has_factory:
@@ -2235,25 +2350,24 @@ def _attrs_to_init_script(
)
)
names_for_globals[init_factory_name] = a.default.factory
- else:
- if a.converter is not None:
- lines.append(
- fmt_setter_with_converter(
- attr_name,
- f"attr_dict['{attr_name}'].default",
- has_on_setattr,
- )
+ elif a.converter is not None:
+ lines.append(
+ fmt_setter_with_converter(
+ attr_name,
+ f"attr_dict['{attr_name}'].default",
+ has_on_setattr,
)
- conv_name = _init_converter_pat % (a.name,)
- names_for_globals[conv_name] = a.converter
- else:
- lines.append(
- fmt_setter(
- attr_name,
- f"attr_dict['{attr_name}'].default",
- has_on_setattr,
- )
+ )
+ conv_name = _init_converter_pat % (a.name,)
+ names_for_globals[conv_name] = a.converter
+ else:
+ lines.append(
+ fmt_setter(
+ attr_name,
+ f"attr_dict['{attr_name}'].default",
+ has_on_setattr,
)
+ )
elif a.default is not NOTHING and not has_factory:
arg = f"{arg_name}=attr_dict['{attr_name}'].default"
if a.kw_only:
@@ -2362,7 +2476,7 @@ def _attrs_to_init_script(
# hash code would result in silent bugs.
if cache_hash:
if frozen:
- if slots:
+ if slots: # noqa: SIM108
# if frozen and slots, then _setattr defined above
init_hash_cache = "_setattr('%s', %s)"
else:
@@ -2380,11 +2494,23 @@ def _attrs_to_init_script(
lines.append(f"BaseException.__init__(self, {vals})")
args = ", ".join(args)
+ pre_init_args = args
if kw_only_args:
args += "%s*, %s" % (
", " if args else "", # leading comma
", ".join(kw_only_args), # kw_only args
)
+ pre_init_kw_only_args = ", ".join(
+ ["%s=%s" % (kw_arg, kw_arg) for kw_arg in kw_only_args]
+ )
+ pre_init_args += (
+ ", " if pre_init_args else ""
+ ) # handle only kwargs and no regular args
+ pre_init_args += pre_init_kw_only_args
+
+ if pre_init and pre_init_has_args:
+ # If pre init method has arguments, pass same arguments as `__init__`
+ lines[0] = "self.__attrs_pre_init__(%s)" % pre_init_args
return (
"def %s(self, %s):\n %s\n"
@@ -2537,9 +2663,8 @@ class Attribute:
if type is None:
type = ca.type
elif ca.type is not None:
- raise ValueError(
- "Type annotation and type argument cannot both be present"
- )
+ msg = "Type annotation and type argument cannot both be present"
+ raise ValueError(msg)
inst_dict = {
k: getattr(ca, k)
for k in Attribute.__slots__
@@ -2663,36 +2788,37 @@ class _CountingAttr:
"on_setattr",
"alias",
)
- __attrs_attrs__ = tuple(
- Attribute(
- name=name,
- alias=_default_init_alias_for(name),
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- hash=True,
- init=True,
- kw_only=False,
- eq=True,
- eq_key=None,
- order=False,
- order_key=None,
- inherited=False,
- on_setattr=None,
- )
- for name in (
- "counter",
- "_default",
- "repr",
- "eq",
- "order",
- "hash",
- "init",
- "on_setattr",
- "alias",
- )
- ) + (
+ __attrs_attrs__ = (
+ *tuple(
+ Attribute(
+ name=name,
+ alias=_default_init_alias_for(name),
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ hash=True,
+ init=True,
+ kw_only=False,
+ eq=True,
+ eq_key=None,
+ order=False,
+ order_key=None,
+ inherited=False,
+ on_setattr=None,
+ )
+ for name in (
+ "counter",
+ "_default",
+ "repr",
+ "eq",
+ "order",
+ "hash",
+ "init",
+ "on_setattr",
+ "alias",
+ )
+ ),
Attribute(
name="metadata",
alias="metadata",
@@ -2839,7 +2965,9 @@ _f = [
Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
-def make_class(name, attrs, bases=(object,), **attributes_arguments):
+def make_class(
+ name, attrs, bases=(object,), class_body=None, **attributes_arguments
+):
r"""
A quick way to create a new class called *name* with *attrs*.
@@ -2855,6 +2983,8 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
:param tuple bases: Classes that the new class will subclass.
+ :param dict class_body: An optional dictionary of class attributes for the new class.
+
:param attributes_arguments: Passed unmodified to `attr.s`.
:return: A new class with *attrs*.
@@ -2862,19 +2992,23 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
.. versionadded:: 17.1.0 *bases*
.. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained.
+ .. versionchanged:: 23.2.0 *class_body*
"""
if isinstance(attrs, dict):
cls_dict = attrs
elif isinstance(attrs, (list, tuple)):
cls_dict = {a: attrib() for a in attrs}
else:
- raise TypeError("attrs argument must be a dict or a list.")
+ msg = "attrs argument must be a dict or a list."
+ raise TypeError(msg)
pre_init = cls_dict.pop("__attrs_pre_init__", None)
post_init = cls_dict.pop("__attrs_post_init__", None)
user_init = cls_dict.pop("__init__", None)
body = {}
+ if class_body is not None:
+ body.update(class_body)
if pre_init is not None:
body["__attrs_pre_init__"] = pre_init
if post_init is not None:
@@ -2888,12 +3022,10 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
# frame where the class is created. Bypass this step in environments where
# sys._getframe is not defined (Jython for example) or sys._getframe is not
# defined for arguments greater than 0 (IronPython).
- try:
+ with contextlib.suppress(AttributeError, ValueError):
type_.__module__ = sys._getframe(1).f_globals.get(
"__name__", "__main__"
)
- except (AttributeError, ValueError):
- pass
# We do it here for proper warnings with meaningful stacklevel.
cmp = attributes_arguments.pop("cmp", None)
diff --git a/contrib/python/attrs/py3/attr/_next_gen.py b/contrib/python/attrs/py3/attr/_next_gen.py
index 8f7c0b9a46..1fb9f259b5 100644
--- a/contrib/python/attrs/py3/attr/_next_gen.py
+++ b/contrib/python/attrs/py3/attr/_next_gen.py
@@ -52,14 +52,14 @@ def define(
- Automatically detect whether or not *auto_attribs* should be `True` (c.f.
*auto_attribs* parameter).
- - If *frozen* is `False`, run converters and validators when setting an
- attribute by default.
+ - Converters and validators run when attributes are set by default -- if
+ *frozen* is `False`.
- *slots=True*
.. caution::
Usually this has only upsides and few visible effects in everyday
- programming. But it *can* lead to some suprising behaviors, so please
+ programming. But it *can* lead to some surprising behaviors, so please
make sure to read :term:`slotted classes`.
- *auto_exc=True*
- *auto_detect=True*
@@ -131,10 +131,8 @@ def define(
for base_cls in cls.__bases__:
if base_cls.__setattr__ is _frozen_setattrs:
if had_on_setattr:
- raise ValueError(
- "Frozen classes can't use on_setattr "
- "(frozen-ness was inherited)."
- )
+ msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)."
+ raise ValueError(msg)
on_setattr = setters.NO_OP
break
@@ -151,8 +149,8 @@ def define(
# if it's used as `@attrs` but ``None`` if used as `@attrs()`.
if maybe_cls is None:
return wrap
- else:
- return wrap(maybe_cls)
+
+ return wrap(maybe_cls)
mutable = define
@@ -181,9 +179,8 @@ def field(
removed.
.. versionadded:: 23.1.0
- The *type* parameter has been re-added; mostly for
- {func}`attrs.make_class`. Please note that type checkers ignore this
- metadata.
+ The *type* parameter has been re-added; mostly for `attrs.make_class`.
+ Please note that type checkers ignore this metadata.
.. versionadded:: 20.1.0
"""
return attrib(
diff --git a/contrib/python/attrs/py3/attr/converters.py b/contrib/python/attrs/py3/attr/converters.py
index 4cada106b0..2bf4c902a6 100644
--- a/contrib/python/attrs/py3/attr/converters.py
+++ b/contrib/python/attrs/py3/attr/converters.py
@@ -70,21 +70,20 @@ def default_if_none(default=NOTHING, factory=None):
.. versionadded:: 18.2.0
"""
if default is NOTHING and factory is None:
- raise TypeError("Must pass either `default` or `factory`.")
+ msg = "Must pass either `default` or `factory`."
+ raise TypeError(msg)
if default is not NOTHING and factory is not None:
- raise TypeError(
- "Must pass either `default` or `factory` but not both."
- )
+ msg = "Must pass either `default` or `factory` but not both."
+ raise TypeError(msg)
if factory is not None:
default = Factory(factory)
if isinstance(default, Factory):
if default.takes_self:
- raise ValueError(
- "`takes_self` is not supported by default_if_none."
- )
+ msg = "`takes_self` is not supported by default_if_none."
+ raise ValueError(msg)
def default_if_none_converter(val):
if val is not None:
@@ -141,4 +140,5 @@ def to_bool(val):
except TypeError:
# Raised when "val" is not hashable (e.g., lists)
pass
- raise ValueError(f"Cannot convert value to bool: {val}")
+ msg = f"Cannot convert value to bool: {val}"
+ raise ValueError(msg)
diff --git a/contrib/python/attrs/py3/attr/exceptions.py b/contrib/python/attrs/py3/attr/exceptions.py
index 2883493085..3b7abb8154 100644
--- a/contrib/python/attrs/py3/attr/exceptions.py
+++ b/contrib/python/attrs/py3/attr/exceptions.py
@@ -1,5 +1,9 @@
# SPDX-License-Identifier: MIT
+from __future__ import annotations
+
+from typing import ClassVar
+
class FrozenError(AttributeError):
"""
@@ -13,7 +17,7 @@ class FrozenError(AttributeError):
"""
msg = "can't set attribute"
- args = [msg]
+ args: ClassVar[tuple[str]] = [msg]
class FrozenInstanceError(FrozenError):
diff --git a/contrib/python/attrs/py3/attr/validators.py b/contrib/python/attrs/py3/attr/validators.py
index 1488554f78..34d6b761d3 100644
--- a/contrib/python/attrs/py3/attr/validators.py
+++ b/contrib/python/attrs/py3/attr/validators.py
@@ -97,23 +97,21 @@ class _InstanceOfValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if not isinstance(value, self.type):
+ msg = "'{name}' must be {type!r} (got {value!r} that is a {actual!r}).".format(
+ name=attr.name,
+ type=self.type,
+ actual=value.__class__,
+ value=value,
+ )
raise TypeError(
- "'{name}' must be {type!r} (got {value!r} that is a "
- "{actual!r}).".format(
- name=attr.name,
- type=self.type,
- actual=value.__class__,
- value=value,
- ),
+ msg,
attr,
self.type,
value,
)
def __repr__(self):
- return "<instance_of validator for type {type!r}>".format(
- type=self.type
- )
+ return f"<instance_of validator for type {self.type!r}>"
def instance_of(type):
@@ -142,20 +140,18 @@ class _MatchesReValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if not self.match_func(value):
+ msg = "'{name}' must match regex {pattern!r} ({value!r} doesn't)".format(
+ name=attr.name, pattern=self.pattern.pattern, value=value
+ )
raise ValueError(
- "'{name}' must match regex {pattern!r}"
- " ({value!r} doesn't)".format(
- name=attr.name, pattern=self.pattern.pattern, value=value
- ),
+ msg,
attr,
self.pattern,
value,
)
def __repr__(self):
- return "<matches_re validator for pattern {pattern!r}>".format(
- pattern=self.pattern
- )
+ return f"<matches_re validator for pattern {self.pattern!r}>"
def matches_re(regex, flags=0, func=None):
@@ -176,22 +172,17 @@ def matches_re(regex, flags=0, func=None):
"""
valid_funcs = (re.fullmatch, None, re.search, re.match)
if func not in valid_funcs:
- raise ValueError(
- "'func' must be one of {}.".format(
- ", ".join(
- sorted(
- e and e.__name__ or "None" for e in set(valid_funcs)
- )
- )
+ msg = "'func' must be one of {}.".format(
+ ", ".join(
+ sorted(e and e.__name__ or "None" for e in set(valid_funcs))
)
)
+ raise ValueError(msg)
if isinstance(regex, Pattern):
if flags:
- raise TypeError(
- "'flags' can only be used with a string pattern; "
- "pass flags to re.compile() instead"
- )
+ msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead"
+ raise TypeError(msg)
pattern = regex
else:
pattern = re.compile(regex, flags)
@@ -215,20 +206,18 @@ class _ProvidesValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if not self.interface.providedBy(value):
+ msg = "'{name}' must provide {interface!r} which {value!r} doesn't.".format(
+ name=attr.name, interface=self.interface, value=value
+ )
raise TypeError(
- "'{name}' must provide {interface!r} which {value!r} "
- "doesn't.".format(
- name=attr.name, interface=self.interface, value=value
- ),
+ msg,
attr,
self.interface,
value,
)
def __repr__(self):
- return "<provides validator for interface {interface!r}>".format(
- interface=self.interface
- )
+ return f"<provides validator for interface {self.interface!r}>"
def provides(interface):
@@ -269,9 +258,7 @@ class _OptionalValidator:
self.validator(inst, attr, value)
def __repr__(self):
- return "<optional validator for {what} or None>".format(
- what=repr(self.validator)
- )
+ return f"<optional validator for {self.validator!r} or None>"
def optional(validator):
@@ -304,19 +291,16 @@ class _InValidator:
in_options = False
if not in_options:
+ msg = f"'{attr.name}' must be in {self.options!r} (got {value!r})"
raise ValueError(
- "'{name}' must be in {options!r} (got {value!r})".format(
- name=attr.name, options=self.options, value=value
- ),
+ msg,
attr,
self.options,
value,
)
def __repr__(self):
- return "<in_ validator with options {options!r}>".format(
- options=self.options
- )
+ return f"<in_ validator with options {self.options!r}>"
def in_(options):
@@ -402,11 +386,8 @@ class _DeepIterable:
else f" {self.iterable_validator!r}"
)
return (
- "<deep_iterable validator for{iterable_identifier}"
- " iterables of {member!r}>"
- ).format(
- iterable_identifier=iterable_identifier,
- member=self.member_validator,
+ f"<deep_iterable validator for{iterable_identifier}"
+ f" iterables of {self.member_validator!r}>"
)
@@ -477,19 +458,11 @@ class _NumberValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if not self.compare_func(value, self.bound):
- raise ValueError(
- "'{name}' must be {op} {bound}: {value}".format(
- name=attr.name,
- op=self.compare_op,
- bound=self.bound,
- value=value,
- )
- )
+ msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}"
+ raise ValueError(msg)
def __repr__(self):
- return "<Validator for x {op} {bound}>".format(
- op=self.compare_op, bound=self.bound
- )
+ return f"<Validator for x {self.compare_op} {self.bound}>"
def lt(val):
@@ -549,11 +522,8 @@ class _MaxLengthValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if len(value) > self.max_length:
- raise ValueError(
- "Length of '{name}' must be <= {max}: {len}".format(
- name=attr.name, max=self.max_length, len=len(value)
- )
- )
+ msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}"
+ raise ValueError(msg)
def __repr__(self):
return f"<max_len validator for {self.max_length}>"
@@ -580,11 +550,8 @@ class _MinLengthValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if len(value) < self.min_length:
- raise ValueError(
- "Length of '{name}' must be => {min}: {len}".format(
- name=attr.name, min=self.min_length, len=len(value)
- )
- )
+ msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}"
+ raise ValueError(msg)
def __repr__(self):
return f"<min_len validator for {self.min_length}>"
@@ -611,22 +578,16 @@ class _SubclassOfValidator:
We use a callable class to be able to change the ``__repr__``.
"""
if not issubclass(value, self.type):
+ msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})."
raise TypeError(
- "'{name}' must be a subclass of {type!r} "
- "(got {value!r}).".format(
- name=attr.name,
- type=self.type,
- value=value,
- ),
+ msg,
attr,
self.type,
value,
)
def __repr__(self):
- return "<subclass_of validator for type {type!r}>".format(
- type=self.type
- )
+ return f"<subclass_of validator for type {self.type!r}>"
def _subclass_of(type):
@@ -680,7 +641,7 @@ class _NotValidator:
def __repr__(self):
return (
- "<not_ validator wrapping {what!r}, " "capturing {exc_types!r}>"
+ "<not_ validator wrapping {what!r}, capturing {exc_types!r}>"
).format(
what=self.validator,
exc_types=self.exc_types,
diff --git a/contrib/python/attrs/py3/attrs/converters.py b/contrib/python/attrs/py3/attrs/converters.py
index edfa8d3c16..7821f6c02c 100644
--- a/contrib/python/attrs/py3/attrs/converters.py
+++ b/contrib/python/attrs/py3/attrs/converters.py
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: MIT
-from attr.converters import * # noqa
+from attr.converters import * # noqa: F403
diff --git a/contrib/python/attrs/py3/attrs/exceptions.py b/contrib/python/attrs/py3/attrs/exceptions.py
index bd9efed202..3323f9d211 100644
--- a/contrib/python/attrs/py3/attrs/exceptions.py
+++ b/contrib/python/attrs/py3/attrs/exceptions.py
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: MIT
-from attr.exceptions import * # noqa
+from attr.exceptions import * # noqa: F403
diff --git a/contrib/python/attrs/py3/attrs/filters.py b/contrib/python/attrs/py3/attrs/filters.py
index 52959005b0..3080f48398 100644
--- a/contrib/python/attrs/py3/attrs/filters.py
+++ b/contrib/python/attrs/py3/attrs/filters.py
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: MIT
-from attr.filters import * # noqa
+from attr.filters import * # noqa: F403
diff --git a/contrib/python/attrs/py3/attrs/setters.py b/contrib/python/attrs/py3/attrs/setters.py
index 9b50770804..f3d73bb793 100644
--- a/contrib/python/attrs/py3/attrs/setters.py
+++ b/contrib/python/attrs/py3/attrs/setters.py
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: MIT
-from attr.setters import * # noqa
+from attr.setters import * # noqa: F403
diff --git a/contrib/python/attrs/py3/attrs/validators.py b/contrib/python/attrs/py3/attrs/validators.py
index ab2c9b3024..037e124f29 100644
--- a/contrib/python/attrs/py3/attrs/validators.py
+++ b/contrib/python/attrs/py3/attrs/validators.py
@@ -1,3 +1,3 @@
# SPDX-License-Identifier: MIT
-from attr.validators import * # noqa
+from attr.validators import * # noqa: F403
diff --git a/contrib/python/attrs/py3/ya.make b/contrib/python/attrs/py3/ya.make
index 842a03879c..e36f5d0ca3 100644
--- a/contrib/python/attrs/py3/ya.make
+++ b/contrib/python/attrs/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(23.1.0)
+VERSION(23.2.0)
LICENSE(MIT)