Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/attr/_compat.py: 76%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# SPDX-License-Identifier: MIT
3import inspect
4import platform
5import sys
6import threading
8from collections.abc import Mapping, Sequence # noqa: F401
9from typing import _GenericAlias
12PYPY = platform.python_implementation() == "PyPy"
13PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
14PY_3_11_PLUS = sys.version_info[:2] >= (3, 11)
15PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
16PY_3_13_PLUS = sys.version_info[:2] >= (3, 13)
17PY_3_14_PLUS = sys.version_info[:2] >= (3, 14)
20if PY_3_14_PLUS:
21 import annotationlib
23 # We request forward-ref annotations to not break in the presence of
24 # forward references.
26 def _get_annotations(cls):
27 return annotationlib.get_annotations(
28 cls, format=annotationlib.Format.FORWARDREF
29 )
31else:
33 def _get_annotations(cls):
34 """
35 Get annotations for *cls*.
36 """
37 return cls.__dict__.get("__annotations__", {})
40class _AnnotationExtractor:
41 """
42 Extract type annotations from a callable, returning None whenever there
43 is none.
44 """
46 __slots__ = ["sig"]
48 def __init__(self, callable):
49 try:
50 self.sig = inspect.signature(callable)
51 except (ValueError, TypeError): # inspect failed
52 self.sig = None
54 def get_first_param_type(self):
55 """
56 Return the type annotation of the first argument if it's not empty.
57 """
58 if not self.sig:
59 return None
61 params = list(self.sig.parameters.values())
62 if params and params[0].annotation is not inspect.Parameter.empty:
63 return params[0].annotation
65 return None
67 def get_return_type(self):
68 """
69 Return the return type if it's not empty.
70 """
71 if (
72 self.sig
73 and self.sig.return_annotation is not inspect.Signature.empty
74 ):
75 return self.sig.return_annotation
77 return None
80# Thread-local global to track attrs instances which are already being repr'd.
81# This is needed because there is no other (thread-safe) way to pass info
82# about the instances that are already being repr'd through the call stack
83# in order to ensure we don't perform infinite recursion.
84#
85# For instance, if an instance contains a dict which contains that instance,
86# we need to know that we're already repr'ing the outside instance from within
87# the dict's repr() call.
88#
89# This lives here rather than in _make.py so that the functions in _make.py
90# don't have a direct reference to the thread-local in their globals dict.
91# If they have such a reference, it breaks cloudpickle.
92repr_context = threading.local()
95def get_generic_base(cl):
96 """If this is a generic class (A[str]), return the generic base for it."""
97 if cl.__class__ is _GenericAlias:
98 return cl.__origin__
99 return None