aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/attrs/attr/_make.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:30 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:30 +0300
commit2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch)
tree012bb94d777798f1f56ac1cec429509766d05181 /contrib/python/attrs/attr/_make.py
parent6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff)
downloadydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/attrs/attr/_make.py')
-rw-r--r--contrib/python/attrs/attr/_make.py980
1 files changed, 490 insertions, 490 deletions
diff --git a/contrib/python/attrs/attr/_make.py b/contrib/python/attrs/attr/_make.py
index a1912b1233..067a25d3f9 100644
--- a/contrib/python/attrs/attr/_make.py
+++ b/contrib/python/attrs/attr/_make.py
@@ -1,7 +1,7 @@
from __future__ import absolute_import, division, print_function
import copy
-import inspect
+import inspect
import linecache
import sys
import threading
@@ -13,11 +13,11 @@ from operator import itemgetter
from . import _config, setters
from ._compat import (
PY2,
- PYPY,
+ PYPY,
isclass,
iteritems,
metadata_proxy,
- new_class,
+ new_class,
ordered_dict,
set_closure_cell,
)
@@ -30,10 +30,10 @@ from .exceptions import (
)
-if not PY2:
- import typing
-
-
+if not PY2:
+ import typing
+
+
# This is used at least twice, so cache it here.
_obj_setattr = object.__setattr__
_init_converter_pat = "__attr_converter_%s"
@@ -41,12 +41,12 @@ _init_factory_pat = "__attr_factory_{}"
_tuple_property_pat = (
" {attr_name} = _attrs_property(_attrs_itemgetter({index}))"
)
-_classvar_prefixes = (
- "typing.ClassVar",
- "t.ClassVar",
- "ClassVar",
- "typing_extensions.ClassVar",
-)
+_classvar_prefixes = (
+ "typing.ClassVar",
+ "t.ClassVar",
+ "ClassVar",
+ "typing_extensions.ClassVar",
+)
# we don't use a double-underscore prefix because that triggers
# name mangling when trying to create a slot for the field
# (when slots=True)
@@ -63,8 +63,8 @@ class _Nothing(object):
Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
``_Nothing`` is a singleton. There is only ever one of it.
-
- .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.
+
+ .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.
"""
_singleton = None
@@ -77,13 +77,13 @@ class _Nothing(object):
def __repr__(self):
return "NOTHING"
- def __bool__(self):
- return False
-
- def __len__(self):
- return 0 # __bool__ for Python 2
-
+ def __bool__(self):
+ return False
+ def __len__(self):
+ return 0 # __bool__ for Python 2
+
+
NOTHING = _Nothing()
"""
Sentinel to indicate the lack of a value when ``None`` is ambiguous.
@@ -184,25 +184,25 @@ def attrib(
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
+
+ :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.
- :type eq: a `bool` or a `callable`.
-
- :param order: If ``True`` (default), include this attributes in the
+ 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.
+ :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.
- :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*.
- :type cmp: a `bool` or a `callable`.
-
+ To override how the attribute value is ordered,
+ pass a ``callable`` that takes a single value and returns the value
+ to be ordered.
+ :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*.
+ :type cmp: a `bool` or a `callable`.
+
:param Optional[bool] 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
@@ -250,19 +250,19 @@ def attrib(
.. versionadded:: 18.1.0
``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
.. versionadded:: 18.2.0 *kw_only*
- .. versionchanged:: 19.2.0 *convert* keyword argument removed.
+ .. versionchanged:: 19.2.0 *convert* keyword argument removed.
.. versionchanged:: 19.2.0 *repr* also accepts a custom callable.
.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
.. versionadded:: 19.2.0 *eq* and *order*
.. versionadded:: 20.1.0 *on_setattr*
- .. versionchanged:: 20.3.0 *kw_only* backported to Python 2
- .. versionchanged:: 21.1.0
- *eq*, *order*, and *cmp* also accept a custom callable
- .. versionchanged:: 21.1.0 *cmp* undeprecated
+ .. versionchanged:: 20.3.0 *kw_only* backported to Python 2
+ .. versionchanged:: 21.1.0
+ *eq*, *order*, and *cmp* also accept a custom callable
+ .. versionchanged:: 21.1.0 *cmp* undeprecated
"""
- eq, eq_key, order, order_key = _determine_attrib_eq_order(
- cmp, eq, order, True
- )
+ eq, eq_key, order, order_key = _determine_attrib_eq_order(
+ cmp, eq, order, True
+ )
if hash is not None and hash is not True and hash is not False:
raise TypeError(
@@ -304,43 +304,43 @@ def attrib(
type=type,
kw_only=kw_only,
eq=eq,
- eq_key=eq_key,
+ eq_key=eq_key,
order=order,
- order_key=order_key,
+ order_key=order_key,
on_setattr=on_setattr,
)
-def _compile_and_eval(script, globs, locs=None, filename=""):
- """
- "Exec" the script with the given global (globs) and local (locs) variables.
- """
- bytecode = compile(script, filename, "exec")
- eval(bytecode, globs, locs)
-
-
-def _make_method(name, script, filename, globs=None):
- """
- Create the method with the script given and return the method object.
- """
- locs = {}
- if globs is None:
- globs = {}
-
- _compile_and_eval(script, globs, locs, filename)
-
- # In order of debuggers like PDB being able to step through the code,
- # we add a fake linecache entry.
- linecache.cache[filename] = (
- len(script),
- None,
- script.splitlines(True),
- filename,
- )
-
- return locs[name]
-
-
+def _compile_and_eval(script, globs, locs=None, filename=""):
+ """
+ "Exec" the script with the given global (globs) and local (locs) variables.
+ """
+ bytecode = compile(script, filename, "exec")
+ eval(bytecode, globs, locs)
+
+
+def _make_method(name, script, filename, globs=None):
+ """
+ Create the method with the script given and return the method object.
+ """
+ locs = {}
+ if globs is None:
+ globs = {}
+
+ _compile_and_eval(script, globs, locs, filename)
+
+ # In order of debuggers like PDB being able to step through the code,
+ # we add a fake linecache entry.
+ linecache.cache[filename] = (
+ len(script),
+ None,
+ script.splitlines(True),
+ filename,
+ )
+
+ return locs[name]
+
+
def _make_attr_tuple_class(cls_name, attr_names):
"""
Create a tuple subclass to hold `Attribute`s for an `attrs` class.
@@ -364,7 +364,7 @@ def _make_attr_tuple_class(cls_name, attr_names):
else:
attr_class_template.append(" pass")
globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
- _compile_and_eval("\n".join(attr_class_template), globs)
+ _compile_and_eval("\n".join(attr_class_template), globs)
return globs[attr_class_name]
@@ -391,15 +391,15 @@ def _is_class_var(annot):
annotations which would put attrs-based classes at a performance
disadvantage compared to plain old classes.
"""
- annot = str(annot)
-
- # Annotation can be quoted.
- if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):
- annot = annot[1:-1]
-
- return annot.startswith(_classvar_prefixes)
+ annot = str(annot)
+ # Annotation can be quoted.
+ if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):
+ annot = annot[1:-1]
+ return annot.startswith(_classvar_prefixes)
+
+
def _has_own_attribute(cls, attrib_name):
"""
Check whether *cls* defines *attrib_name* (and doesn't just inherit it).
@@ -448,7 +448,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)
base_attrs.append(a)
base_attr_map[a.name] = base_cls
@@ -486,7 +486,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)
taken_attr_names.add(a.name)
base_attrs.append(a)
base_attr_map[a.name] = base_cls
@@ -494,9 +494,9 @@ def _collect_base_attrs_broken(cls, taken_attr_names):
return base_attrs, base_attr_map
-def _transform_attrs(
- cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer
-):
+def _transform_attrs(
+ cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer
+):
"""
Transform all `_CountingAttr`s on a class into `Attribute`s.
@@ -528,7 +528,7 @@ def _transform_attrs(
continue
annot_names.add(attr_name)
a = cd.get(attr_name, NOTHING)
-
+
if not isinstance(a, _CountingAttr):
if a is NOTHING:
a = attrib()
@@ -576,8 +576,8 @@ def _transform_attrs(
AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
if kw_only:
- own_attrs = [a.evolve(kw_only=True) for a in own_attrs]
- base_attrs = [a.evolve(kw_only=True) for a in base_attrs]
+ own_attrs = [a.evolve(kw_only=True) for a in own_attrs]
+ base_attrs = [a.evolve(kw_only=True) for a in base_attrs]
attrs = AttrsClass(base_attrs + own_attrs)
@@ -596,36 +596,36 @@ def _transform_attrs(
if had_default is False and a.default is not NOTHING:
had_default = True
- if field_transformer is not None:
- attrs = field_transformer(cls, attrs)
+ if field_transformer is not None:
+ attrs = field_transformer(cls, attrs)
return _Attributes((attrs, base_attrs, base_attr_map))
-if PYPY:
-
- def _frozen_setattrs(self, name, value):
- """
- Attached to frozen classes as __setattr__.
- """
- if isinstance(self, BaseException) and name in (
- "__cause__",
- "__context__",
- ):
- BaseException.__setattr__(self, name, value)
- return
-
- raise FrozenInstanceError()
-
-
-else:
-
- def _frozen_setattrs(self, name, value):
- """
- Attached to frozen classes as __setattr__.
- """
- raise FrozenInstanceError()
-
-
+if PYPY:
+
+ def _frozen_setattrs(self, name, value):
+ """
+ Attached to frozen classes as __setattr__.
+ """
+ if isinstance(self, BaseException) and name in (
+ "__cause__",
+ "__context__",
+ ):
+ BaseException.__setattr__(self, name, value)
+ return
+
+ raise FrozenInstanceError()
+
+
+else:
+
+ def _frozen_setattrs(self, name, value):
+ """
+ Attached to frozen classes as __setattr__.
+ """
+ raise FrozenInstanceError()
+
+
def _frozen_delattrs(self, name):
"""
Attached to frozen classes as __delattr__.
@@ -648,9 +648,9 @@ class _ClassBuilder(object):
"_cls_dict",
"_delete_attribs",
"_frozen",
- "_has_pre_init",
+ "_has_pre_init",
"_has_post_init",
- "_is_exc",
+ "_is_exc",
"_on_setattr",
"_slots",
"_weakref_slot",
@@ -669,19 +669,19 @@ class _ClassBuilder(object):
auto_attribs,
kw_only,
cache_hash,
- is_exc,
+ is_exc,
collect_by_mro,
on_setattr,
has_custom_setattr,
- field_transformer,
+ field_transformer,
):
attrs, base_attrs, base_map = _transform_attrs(
- cls,
- these,
- auto_attribs,
- kw_only,
- collect_by_mro,
- field_transformer,
+ cls,
+ these,
+ auto_attribs,
+ kw_only,
+ collect_by_mro,
+ field_transformer,
)
self._cls = cls
@@ -694,10 +694,10 @@ class _ClassBuilder(object):
self._frozen = frozen
self._weakref_slot = weakref_slot
self._cache_hash = cache_hash
- self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
+ self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
self._delete_attribs = not bool(these)
- self._is_exc = is_exc
+ self._is_exc = is_exc
self._on_setattr = on_setattr
self._has_custom_setattr = has_custom_setattr
@@ -743,7 +743,7 @@ class _ClassBuilder(object):
for name in self._attr_names:
if (
name not in base_names
- and getattr(cls, name, _sentinel) is not _sentinel
+ and getattr(cls, name, _sentinel) is not _sentinel
):
try:
delattr(cls, name)
@@ -763,10 +763,10 @@ class _ClassBuilder(object):
cls, "__attrs_own_setattr__", False
):
cls.__attrs_own_setattr__ = False
-
+
if not self._has_custom_setattr:
cls.__setattr__ = object.__setattr__
-
+
return cls
def _create_slots_class(self):
@@ -796,22 +796,22 @@ class _ClassBuilder(object):
cd["__setattr__"] = object.__setattr__
break
- # Traverse the MRO to collect existing slots
- # and check for an existing __weakref__.
- existing_slots = dict()
+ # Traverse the MRO to collect existing slots
+ # and check for an existing __weakref__.
+ existing_slots = dict()
weakref_inherited = False
for base_cls in self._cls.__mro__[1:-1]:
if base_cls.__dict__.get("__weakref__", None) is not None:
weakref_inherited = True
- existing_slots.update(
- {
- name: getattr(base_cls, name)
- for name in getattr(base_cls, "__slots__", [])
- }
- )
-
- base_names = set(self._base_names)
-
+ existing_slots.update(
+ {
+ name: getattr(base_cls, name)
+ for name in getattr(base_cls, "__slots__", [])
+ }
+ )
+
+ base_names = set(self._base_names)
+
names = self._attr_names
if (
self._weakref_slot
@@ -824,17 +824,17 @@ class _ClassBuilder(object):
# 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 overriden by a child class,
- # we collect them here and update the class dict
- reused_slots = {
- slot: slot_descriptor
- for slot, slot_descriptor in iteritems(existing_slots)
- if slot in slot_names
- }
- slot_names = [name for name in slot_names if name not in reused_slots]
- cd.update(reused_slots)
+ # There are slots for attributes from current class
+ # that are defined in parent classes.
+ # As their descriptors may be overriden by a child class,
+ # we collect them here and update the class dict
+ reused_slots = {
+ slot: slot_descriptor
+ for slot, slot_descriptor in iteritems(existing_slots)
+ if slot in slot_names
+ }
+ slot_names = [name for name in slot_names if name not in reused_slots]
+ cd.update(reused_slots)
if self._cache_hash:
slot_names.append(_hash_cache_field)
cd["__slots__"] = tuple(slot_names)
@@ -857,10 +857,10 @@ class _ClassBuilder(object):
# Class- and staticmethods hide their functions inside.
# These might need to be rewritten as well.
closure_cells = getattr(item.__func__, "__closure__", None)
- elif isinstance(item, property):
- # Workaround for property `super()` shortcut (PY3-only).
- # There is no universal way for other descriptors.
- closure_cells = getattr(item.fget, "__closure__", None)
+ elif isinstance(item, property):
+ # Workaround for property `super()` shortcut (PY3-only).
+ # There is no universal way for other descriptors.
+ closure_cells = getattr(item.fget, "__closure__", None)
else:
closure_cells = getattr(item, "__closure__", None)
@@ -951,41 +951,41 @@ class _ClassBuilder(object):
_make_init(
self._cls,
self._attrs,
- self._has_pre_init,
+ self._has_pre_init,
self._has_post_init,
self._frozen,
self._slots,
self._cache_hash,
self._base_attr_map,
- self._is_exc,
+ self._is_exc,
self._on_setattr is not None
and self._on_setattr is not setters.NO_OP,
- attrs_init=False,
- )
- )
-
- return self
-
- def add_attrs_init(self):
- self._cls_dict["__attrs_init__"] = self._add_method_dunders(
- _make_init(
- self._cls,
- self._attrs,
- self._has_pre_init,
- self._has_post_init,
- self._frozen,
- self._slots,
- self._cache_hash,
- self._base_attr_map,
- self._is_exc,
- self._on_setattr is not None
- and self._on_setattr is not setters.NO_OP,
- attrs_init=True,
+ attrs_init=False,
)
)
return self
+ def add_attrs_init(self):
+ self._cls_dict["__attrs_init__"] = self._add_method_dunders(
+ _make_init(
+ self._cls,
+ self._attrs,
+ self._has_pre_init,
+ self._has_post_init,
+ self._frozen,
+ self._slots,
+ self._cache_hash,
+ self._base_attr_map,
+ self._is_exc,
+ self._on_setattr is not None
+ and self._on_setattr is not setters.NO_OP,
+ attrs_init=True,
+ )
+ )
+
+ return self
+
def add_eq(self):
cd = self._cls_dict
@@ -1074,7 +1074,7 @@ _CMP_DEPRECATION = (
)
-def _determine_attrs_eq_order(cmp, eq, order, default_eq):
+def _determine_attrs_eq_order(cmp, eq, order, default_eq):
"""
Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
values of eq and order. If *eq* is None, set it to *default_eq*.
@@ -1100,47 +1100,47 @@ def _determine_attrs_eq_order(cmp, eq, order, default_eq):
return eq, order
-def _determine_attrib_eq_order(cmp, eq, order, default_eq):
- """
- Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
- 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`.")
-
- def decide_callable_or_boolean(value):
- """
- Decide whether a key function is used.
- """
- if callable(value):
- value, key = True, value
- else:
- key = None
- return value, key
-
- # cmp takes precedence due to bw-compatibility.
- if cmp is not None:
- cmp, cmp_key = decide_callable_or_boolean(cmp)
- return cmp, cmp_key, cmp, cmp_key
-
- # If left None, equality is set to the specified default and ordering
- # mirrors equality.
- if eq is None:
- eq, eq_key = default_eq, None
- else:
- eq, eq_key = decide_callable_or_boolean(eq)
-
- if order is None:
- order, order_key = eq, eq_key
- else:
- 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.")
-
- return eq, eq_key, order, order_key
-
-
+def _determine_attrib_eq_order(cmp, eq, order, default_eq):
+ """
+ Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
+ 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`.")
+
+ def decide_callable_or_boolean(value):
+ """
+ Decide whether a key function is used.
+ """
+ if callable(value):
+ value, key = True, value
+ else:
+ key = None
+ return value, key
+
+ # cmp takes precedence due to bw-compatibility.
+ if cmp is not None:
+ cmp, cmp_key = decide_callable_or_boolean(cmp)
+ return cmp, cmp_key, cmp, cmp_key
+
+ # If left None, equality is set to the specified default and ordering
+ # mirrors equality.
+ if eq is None:
+ eq, eq_key = default_eq, None
+ else:
+ eq, eq_key = decide_callable_or_boolean(eq)
+
+ if order is None:
+ order, order_key = eq, eq_key
+ else:
+ 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.")
+
+ return eq, eq_key, order, order_key
+
+
def _determine_whether_to_implement(
cls, flag, auto_detect, dunders, default=True
):
@@ -1184,14 +1184,14 @@ def attrs(
auto_attribs=False,
kw_only=False,
cache_hash=False,
- auto_exc=False,
+ auto_exc=False,
eq=None,
order=None,
auto_detect=False,
collect_by_mro=False,
getstate_setstate=None,
on_setattr=None,
- field_transformer=None,
+ field_transformer=None,
):
r"""
A class decorator that adds `dunder
@@ -1223,7 +1223,7 @@ def attrs(
inherited from some base class).
So for example by implementing ``__eq__`` on a class yourself,
- ``attrs`` will deduce ``eq=False`` and will create *neither*
+ ``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).
@@ -1256,8 +1256,8 @@ def attrs(
``__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] 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] hash: If ``None`` (default), the ``__hash__`` method
is generated according how *eq* and *frozen* are set.
@@ -1278,28 +1278,28 @@ def attrs(
behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more
details.
: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__()``.
+ ``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__()``.
:param bool slots: Create a `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 we
- encourage you to read the `glossary entry <slotted classes>`.
+ memory-efficient. Slotted classes are generally superior to the default
+ dict classes, but have some gotchas you should know about, so we
+ encourage you to read the `glossary entry <slotted classes>`.
:param bool frozen: Make instances immutable after initialization. If
someone attempts to modify a frozen instance,
`attr.exceptions.FrozenInstanceError` is raised.
- .. note::
+ .. note::
1. This is achieved by installing a custom ``__setattr__`` method
- on your class, so you can't implement your own.
+ on your class, so you can't implement your own.
2. True immutability is impossible in Python.
@@ -1328,20 +1328,20 @@ def attrs(
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
``attr.ib(default=42)``. Passing an instance of `Factory` also
- works as expected in most cases (see warning below).
+ works as expected in most cases (see warning below).
Attributes annotated as `typing.ClassVar`, and attributes that are
neither annotated nor set to an `attr.ib` are **ignored**.
- .. warning::
- For features that use the attribute name to create decorators (e.g.
- `validators <validators>`), you still *must* assign `attr.ib` to
- them. Otherwise Python will either not find the name or try to use
- the default value to call e.g. ``validator`` on it.
-
- These errors can be quite confusing and probably the most common bug
- report on our bug tracker.
-
+ .. warning::
+ For features that use the attribute name to create decorators (e.g.
+ `validators <validators>`), you still *must* assign `attr.ib` to
+ them. Otherwise Python will either not find the name or try to use
+ the default value to call e.g. ``validator`` on it.
+
+ These errors can be quite confusing and probably the most common bug
+ report on our bug tracker.
+
.. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/
:param bool kw_only: Make all attributes keyword-only (Python 3+)
in the generated ``__init__`` (if ``init`` is ``False``, this
@@ -1349,23 +1349,23 @@ def attrs(
: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.
+ 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:
+ (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
*not* remove existing implementations of ``__hash__`` or the equality
methods. It just won't add own ones.),
- - all attributes that are either passed into ``__init__`` or have a
- default value are additionally available as a tuple in the ``args``
- attribute,
- - the value of *str* is ignored leaving ``__str__`` to base classes.
+ - all attributes that are either passed into ``__init__`` or have a
+ default value are additionally available as a tuple in the ``args``
+ attribute,
+ - the value of *str* is ignored leaving ``__str__`` to base classes.
:param bool collect_by_mro: Setting this to `True` fixes the way ``attrs``
collects attributes from base classes. The default behavior is
incorrect in certain cases of multiple inheritance. It should be on by
@@ -1391,7 +1391,7 @@ def attrs(
:param on_setattr: A callable that is run whenever the user attempts to set
an attribute (either by assignment like ``i.x = 42`` or by using
- `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments
+ `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments
as validators: the instance, the attribute that is being modified, and
the new value.
@@ -1401,11 +1401,11 @@ def attrs(
If a list of callables is passed, they're automatically wrapped in an
`attr.setters.pipe`.
- :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 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.
.. versionadded:: 16.0.0 *slots*
.. versionadded:: 16.1.0 *frozen*
@@ -1428,41 +1428,41 @@ def attrs(
subclasses comparable anymore.
.. versionadded:: 18.2.0 *kw_only*
.. versionadded:: 18.2.0 *cache_hash*
- .. versionadded:: 19.1.0 *auto_exc*
+ .. versionadded:: 19.1.0 *auto_exc*
.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
.. versionadded:: 19.2.0 *eq* and *order*
.. versionadded:: 20.1.0 *auto_detect*
.. versionadded:: 20.1.0 *collect_by_mro*
.. versionadded:: 20.1.0 *getstate_setstate*
.. versionadded:: 20.1.0 *on_setattr*
- .. versionadded:: 20.3.0 *field_transformer*
- .. versionchanged:: 21.1.0
- ``init=False`` injects ``__attrs_init__``
- .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``
- .. versionchanged:: 21.1.0 *cmp* undeprecated
+ .. versionadded:: 20.3.0 *field_transformer*
+ .. versionchanged:: 21.1.0
+ ``init=False`` injects ``__attrs_init__``
+ .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``
+ .. versionchanged:: 21.1.0 *cmp* undeprecated
"""
if auto_detect and PY2:
raise PythonTooOldError(
"auto_detect only works on Python 3 and later."
)
- eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)
+ eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)
hash_ = hash # work around the lack of nonlocal
if isinstance(on_setattr, (list, tuple)):
on_setattr = setters.pipe(*on_setattr)
def wrap(cls):
-
+
if getattr(cls, "__class__", None) is None:
raise TypeError("attrs only works with new-style classes.")
is_frozen = frozen or _has_frozen_base_class(cls)
- is_exc = auto_exc is True and issubclass(cls, BaseException)
+ is_exc = auto_exc is True and issubclass(cls, BaseException)
has_own_setattr = auto_detect and _has_own_attribute(
cls, "__setattr__"
)
-
+
if has_own_setattr and is_frozen:
raise ValueError("Can't freeze a class with a custom __setattr__.")
@@ -1482,11 +1482,11 @@ def attrs(
auto_attribs,
kw_only,
cache_hash,
- is_exc,
+ is_exc,
collect_by_mro,
on_setattr,
has_own_setattr,
- field_transformer,
+ field_transformer,
)
if _determine_whether_to_implement(
cls, repr, auto_detect, ("__repr__",)
@@ -1549,7 +1549,7 @@ def attrs(
):
builder.add_init()
else:
- builder.add_attrs_init()
+ builder.add_attrs_init()
if cache_hash:
raise TypeError(
"Invalid value for cache_hash. To use hash caching,"
@@ -1690,7 +1690,7 @@ def _make_hash(cls, attrs, frozen, cache_hash):
append_hash_computation_lines("return ", tab)
script = "\n".join(method_lines)
- return _make_method("__hash__", script, unique_filename)
+ return _make_method("__hash__", script, unique_filename)
def _add_hash(cls, attrs):
@@ -1732,36 +1732,36 @@ def _make_eq(cls, attrs):
" if other.__class__ is not self.__class__:",
" return NotImplemented",
]
-
+
# We can't just do a big self.x = other.x and... clause due to
# irregularities like nan == nan is false but (nan,) == (nan,) is true.
- globs = {}
+ globs = {}
if attrs:
lines.append(" return (")
others = [" ) == ("]
for a in attrs:
- if a.eq_key:
- cmp_name = "_%s_key" % (a.name,)
- # Add the key function to the global namespace
- # of the evaluated function.
- globs[cmp_name] = a.eq_key
- lines.append(
- " %s(self.%s),"
- % (
- cmp_name,
- a.name,
- )
- )
- others.append(
- " %s(other.%s),"
- % (
- cmp_name,
- a.name,
- )
- )
- else:
- lines.append(" self.%s," % (a.name,))
- others.append(" other.%s," % (a.name,))
+ if a.eq_key:
+ cmp_name = "_%s_key" % (a.name,)
+ # Add the key function to the global namespace
+ # of the evaluated function.
+ globs[cmp_name] = a.eq_key
+ lines.append(
+ " %s(self.%s),"
+ % (
+ cmp_name,
+ a.name,
+ )
+ )
+ others.append(
+ " %s(other.%s),"
+ % (
+ cmp_name,
+ a.name,
+ )
+ )
+ else:
+ lines.append(" self.%s," % (a.name,))
+ others.append(" other.%s," % (a.name,))
lines += others + [" )"]
else:
@@ -1769,7 +1769,7 @@ def _make_eq(cls, attrs):
script = "\n".join(lines)
- return _make_method("__eq__", script, unique_filename, globs)
+ return _make_method("__eq__", script, unique_filename, globs)
def _make_order(cls, attrs):
@@ -1782,12 +1782,12 @@ def _make_order(cls, attrs):
"""
Save us some typing.
"""
- return tuple(
- key(value) if key else value
- for value, key in (
- (getattr(obj, a.name), a.order_key) for a in attrs
- )
- )
+ return tuple(
+ key(value) if key else value
+ for value, key in (
+ (getattr(obj, a.name), a.order_key) for a in attrs
+ )
+ )
def __lt__(self, other):
"""
@@ -2001,7 +2001,7 @@ def _is_slot_attr(a_name, base_attr_map):
def _make_init(
cls,
attrs,
- pre_init,
+ pre_init,
post_init,
frozen,
slots,
@@ -2009,7 +2009,7 @@ def _make_init(
base_attr_map,
is_exc,
has_global_on_setattr,
- attrs_init,
+ attrs_init,
):
if frozen and has_global_on_setattr:
raise ValueError("Frozen classes can't use on_setattr.")
@@ -2040,19 +2040,19 @@ def _make_init(
filtered_attrs,
frozen,
slots,
- pre_init,
+ pre_init,
post_init,
cache_hash,
base_attr_map,
is_exc,
needs_cached_setattr,
has_global_on_setattr,
- attrs_init,
+ attrs_init,
)
- if cls.__module__ in sys.modules:
- # This makes typing.get_type_hints(CLS.__init__) resolve string types.
- globs.update(sys.modules[cls.__module__].__dict__)
-
+ if cls.__module__ in sys.modules:
+ # This makes typing.get_type_hints(CLS.__init__) resolve string types.
+ globs.update(sys.modules[cls.__module__].__dict__)
+
globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
if needs_cached_setattr:
@@ -2060,15 +2060,15 @@ def _make_init(
# setattr hooks.
globs["_cached_setattr"] = _obj_setattr
- init = _make_method(
- "__attrs_init__" if attrs_init else "__init__",
- script,
+ init = _make_method(
+ "__attrs_init__" if attrs_init else "__init__",
+ script,
unique_filename,
- globs,
+ globs,
)
- init.__annotations__ = annotations
+ init.__annotations__ = annotations
- return init
+ return init
def _setattr(attr_name, value_var, has_on_setattr):
@@ -2135,12 +2135,12 @@ if PY2:
def _unpack_kw_only_lines_py2(kw_only_args):
"""
Unpack all *kw_only_args* from _kw_only dict and handle errors.
-
+
Given a list of strings "{attr_name}" and "{attr_name}={default}"
generates list of lines of code that pop attrs from _kw_only dict and
raise TypeError similar to builtin if required attr is missing or
extra key is passed.
-
+
>>> print("\n".join(_unpack_kw_only_lines_py2(["a", "b=42"])))
try:
a = _kw_only.pop('a')
@@ -2177,14 +2177,14 @@ def _attrs_to_init_script(
attrs,
frozen,
slots,
- pre_init,
+ pre_init,
post_init,
cache_hash,
base_attr_map,
is_exc,
needs_cached_setattr,
has_global_on_setattr,
- attrs_init,
+ attrs_init,
):
"""
Return a script of an initializer for *attrs* and a dict of globals.
@@ -2195,9 +2195,9 @@ def _attrs_to_init_script(
a cached ``object.__setattr__``.
"""
lines = []
- if pre_init:
- lines.append("self.__attrs_pre_init__()")
-
+ if pre_init:
+ lines.append("self.__attrs_pre_init__()")
+
if needs_cached_setattr:
lines.append(
# Circumvent the __setattr__ descriptor to save one lookup per
@@ -2387,24 +2387,24 @@ def _attrs_to_init_script(
else:
lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
- if a.init is True:
- if a.type is not None and a.converter is None:
- annotations[arg_name] = a.type
- elif a.converter is not None and not PY2:
- # Try to get the type from the converter.
- sig = None
- try:
- sig = inspect.signature(a.converter)
- except (ValueError, TypeError): # inspect failed
- pass
- if sig:
- sig_params = list(sig.parameters.values())
- if (
- sig_params
- and sig_params[0].annotation
- is not inspect.Parameter.empty
- ):
- annotations[arg_name] = sig_params[0].annotation
+ if a.init is True:
+ if a.type is not None and a.converter is None:
+ annotations[arg_name] = a.type
+ elif a.converter is not None and not PY2:
+ # Try to get the type from the converter.
+ sig = None
+ try:
+ sig = inspect.signature(a.converter)
+ except (ValueError, TypeError): # inspect failed
+ pass
+ if sig:
+ sig_params = list(sig.parameters.values())
+ if (
+ sig_params
+ and sig_params[0].annotation
+ is not inspect.Parameter.empty
+ ):
+ annotations[arg_name] = sig_params[0].annotation
if attrs_to_validate: # we can skip this if there are no validators.
names_for_globals["_config"] = _config
@@ -2438,13 +2438,13 @@ def _attrs_to_init_script(
init_hash_cache = "self.%s = %s"
lines.append(init_hash_cache % (_hash_cache_field, "None"))
- # For exceptions we rely on BaseException.__init__ for proper
- # initialization.
- if is_exc:
- vals = ",".join("self." + a.name for a in attrs if a.init)
-
- lines.append("BaseException.__init__(self, %s)" % (vals,))
-
+ # For exceptions we rely on BaseException.__init__ for proper
+ # initialization.
+ if is_exc:
+ vals = ",".join("self." + a.name for a in attrs if a.init)
+
+ lines.append("BaseException.__init__(self, %s)" % (vals,))
+
args = ", ".join(args)
if kw_only_args:
if PY2:
@@ -2458,12 +2458,12 @@ def _attrs_to_init_script(
)
return (
"""\
-def {init_name}(self, {args}):
+def {init_name}(self, {args}):
{lines}
""".format(
- init_name=("__attrs_init__" if attrs_init else "__init__"),
- args=args,
- lines="\n ".join(lines) if lines else "pass",
+ init_name=("__attrs_init__" if attrs_init else "__init__"),
+ args=args,
+ lines="\n ".join(lines) if lines else "pass",
),
names_for_globals,
annotations,
@@ -2474,13 +2474,13 @@ class Attribute(object):
"""
*Read-only* representation of an attribute.
- Instances of this class are frequently used for introspection purposes
- like:
-
- - `fields` returns a tuple of them.
- - Validators get them passed as the first argument.
- - The *field transformer* hook receives a list of them.
-
+ Instances of this class are frequently used for introspection purposes
+ like:
+
+ - `fields` returns a tuple of them.
+ - Validators get them passed as the first argument.
+ - The *field transformer* hook receives a list of them.
+
:attribute name: The name of the attribute.
:attribute inherited: Whether or not that attribute has been inherited from
a base class.
@@ -2492,7 +2492,7 @@ class Attribute(object):
.. versionadded:: 20.1.0 *on_setattr*
.. versionchanged:: 20.2.0 *inherited* is not taken into account for
equality checks and hashing anymore.
- .. versionadded:: 21.1.0 *eq_key* and *order_key*
+ .. versionadded:: 21.1.0 *eq_key* and *order_key*
For the full version history of the fields, see `attr.ib`.
"""
@@ -2503,9 +2503,9 @@ class Attribute(object):
"validator",
"repr",
"eq",
- "eq_key",
+ "eq_key",
"order",
- "order_key",
+ "order_key",
"hash",
"init",
"metadata",
@@ -2531,14 +2531,14 @@ class Attribute(object):
converter=None,
kw_only=False,
eq=None,
- eq_key=None,
+ eq_key=None,
order=None,
- order_key=None,
+ order_key=None,
on_setattr=None,
):
- eq, eq_key, order, order_key = _determine_attrib_eq_order(
- cmp, eq_key or eq, order_key or order, True
- )
+ eq, eq_key, order, order_key = _determine_attrib_eq_order(
+ cmp, eq_key or eq, order_key or order, True
+ )
# Cache this descriptor here to speed things up later.
bound_setattr = _obj_setattr.__get__(self, Attribute)
@@ -2550,9 +2550,9 @@ class Attribute(object):
bound_setattr("validator", validator)
bound_setattr("repr", repr)
bound_setattr("eq", eq)
- bound_setattr("eq_key", eq_key)
+ bound_setattr("eq_key", eq_key)
bound_setattr("order", order)
- bound_setattr("order_key", order_key)
+ bound_setattr("order_key", order_key)
bound_setattr("hash", hash)
bound_setattr("init", init)
bound_setattr("converter", converter)
@@ -2612,17 +2612,17 @@ class Attribute(object):
return self.eq and self.order
- # Don't use attr.evolve since fields(Attribute) doesn't work
- def evolve(self, **changes):
+ # Don't use attr.evolve since fields(Attribute) doesn't work
+ def evolve(self, **changes):
"""
Copy *self* and apply *changes*.
-
- This works similarly to `attr.evolve` but that function does not work
- with ``Attribute``.
-
- It is mainly meant to be used for `transform-fields`.
-
- .. versionadded:: 20.3.0
+
+ This works similarly to `attr.evolve` but that function does not work
+ with ``Attribute``.
+
+ It is mainly meant to be used for `transform-fields`.
+
+ .. versionadded:: 20.3.0
"""
new = copy.copy(self)
@@ -2699,9 +2699,9 @@ class _CountingAttr(object):
"_default",
"repr",
"eq",
- "eq_key",
+ "eq_key",
"order",
- "order_key",
+ "order_key",
"hash",
"init",
"metadata",
@@ -2722,9 +2722,9 @@ class _CountingAttr(object):
init=True,
kw_only=False,
eq=True,
- eq_key=None,
+ eq_key=None,
order=False,
- order_key=None,
+ order_key=None,
inherited=False,
on_setattr=None,
)
@@ -2749,9 +2749,9 @@ class _CountingAttr(object):
init=True,
kw_only=False,
eq=True,
- eq_key=None,
+ eq_key=None,
order=False,
- order_key=None,
+ order_key=None,
inherited=False,
on_setattr=None,
),
@@ -2763,7 +2763,7 @@ class _CountingAttr(object):
default,
validator,
repr,
- cmp,
+ cmp,
hash,
init,
converter,
@@ -2771,9 +2771,9 @@ class _CountingAttr(object):
type,
kw_only,
eq,
- eq_key,
+ eq_key,
order,
- order_key,
+ order_key,
on_setattr,
):
_CountingAttr.cls_counter += 1
@@ -2783,9 +2783,9 @@ class _CountingAttr(object):
self.converter = converter
self.repr = repr
self.eq = eq
- self.eq_key = eq_key
+ self.eq_key = eq_key
self.order = order
- self.order_key = order_key
+ self.order_key = order_key
self.hash = hash
self.init = init
self.metadata = metadata
@@ -2843,7 +2843,7 @@ class Factory(object):
.. versionadded:: 17.1.0 *takes_self*
"""
- __slots__ = ("factory", "takes_self")
+ __slots__ = ("factory", "takes_self")
def __init__(self, factory, takes_self=False):
"""
@@ -2853,39 +2853,39 @@ class Factory(object):
self.factory = factory
self.takes_self = takes_self
- def __getstate__(self):
- """
- Play nice with pickle.
- """
- return tuple(getattr(self, name) for name in self.__slots__)
-
- def __setstate__(self, state):
- """
- Play nice with pickle.
- """
- for name, value in zip(self.__slots__, state):
- setattr(self, name, value)
-
-
-_f = [
- Attribute(
- name=name,
- default=NOTHING,
- validator=None,
- repr=True,
- cmp=None,
- eq=True,
- order=False,
- hash=True,
- init=True,
- inherited=False,
- )
- for name in Factory.__slots__
-]
-
-Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
-
-
+ def __getstate__(self):
+ """
+ Play nice with pickle.
+ """
+ return tuple(getattr(self, name) for name in self.__slots__)
+
+ def __setstate__(self, state):
+ """
+ Play nice with pickle.
+ """
+ for name, value in zip(self.__slots__, state):
+ setattr(self, name, value)
+
+
+_f = [
+ Attribute(
+ name=name,
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ eq=True,
+ order=False,
+ hash=True,
+ init=True,
+ inherited=False,
+ )
+ for name in Factory.__slots__
+]
+
+Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
+
+
def make_class(name, attrs, bases=(object,), **attributes_arguments):
"""
A quick way to create a new class called *name* with *attrs*.
@@ -2918,20 +2918,20 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
else:
raise TypeError("attrs argument must be a dict or a list.")
- pre_init = cls_dict.pop("__attrs_pre_init__", None)
+ 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 pre_init is not None:
- body["__attrs_pre_init__"] = pre_init
- if post_init is not None:
- body["__attrs_post_init__"] = post_init
- if user_init is not None:
- body["__init__"] = user_init
-
- type_ = new_class(name, bases, {}, lambda ns: ns.update(body))
-
+ user_init = cls_dict.pop("__init__", None)
+
+ body = {}
+ if pre_init is not None:
+ body["__attrs_pre_init__"] = pre_init
+ if post_init is not None:
+ body["__attrs_post_init__"] = post_init
+ if user_init is not None:
+ body["__init__"] = user_init
+
+ type_ = new_class(name, bases, {}, lambda ns: ns.update(body))
+
# For pickling to work, the __module__ variable needs to be set to the
# 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
@@ -2948,7 +2948,7 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
(
attributes_arguments["eq"],
attributes_arguments["order"],
- ) = _determine_attrs_eq_order(
+ ) = _determine_attrs_eq_order(
cmp,
attributes_arguments.get("eq"),
attributes_arguments.get("order"),
@@ -3003,9 +3003,9 @@ def pipe(*converters):
When called on a value, it runs all wrapped converters, returning the
*last* value.
- Type annotations will be inferred from the wrapped converters', if
- they have any.
-
+ Type annotations will be inferred from the wrapped converters', if
+ they have any.
+
:param callables converters: Arbitrary number of converters.
.. versionadded:: 20.1.0
@@ -3017,36 +3017,36 @@ def pipe(*converters):
return val
- if not PY2:
- if not converters:
- # If the converter list is empty, pipe_converter is the identity.
- A = typing.TypeVar("A")
- pipe_converter.__annotations__ = {"val": A, "return": A}
- else:
- # Get parameter type.
- sig = None
- try:
- sig = inspect.signature(converters[0])
- except (ValueError, TypeError): # inspect failed
- pass
- if sig:
- params = list(sig.parameters.values())
- if (
- params
- and params[0].annotation is not inspect.Parameter.empty
- ):
- pipe_converter.__annotations__["val"] = params[
- 0
- ].annotation
- # Get return type.
- sig = None
- try:
- sig = inspect.signature(converters[-1])
- except (ValueError, TypeError): # inspect failed
- pass
- if sig and sig.return_annotation is not inspect.Signature().empty:
- pipe_converter.__annotations__[
- "return"
- ] = sig.return_annotation
-
+ if not PY2:
+ if not converters:
+ # If the converter list is empty, pipe_converter is the identity.
+ A = typing.TypeVar("A")
+ pipe_converter.__annotations__ = {"val": A, "return": A}
+ else:
+ # Get parameter type.
+ sig = None
+ try:
+ sig = inspect.signature(converters[0])
+ except (ValueError, TypeError): # inspect failed
+ pass
+ if sig:
+ params = list(sig.parameters.values())
+ if (
+ params
+ and params[0].annotation is not inspect.Parameter.empty
+ ):
+ pipe_converter.__annotations__["val"] = params[
+ 0
+ ].annotation
+ # Get return type.
+ sig = None
+ try:
+ sig = inspect.signature(converters[-1])
+ except (ValueError, TypeError): # inspect failed
+ pass
+ if sig and sig.return_annotation is not inspect.Signature().empty:
+ pipe_converter.__annotations__[
+ "return"
+ ] = sig.return_annotation
+
return pipe_converter