Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/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_8_PLUS = sys.version_info[:2] >= (3, 8)
14PY_3_9_PLUS = sys.version_info[:2] >= (3, 9)
15PY310 = sys.version_info[:2] >= (3, 10)
16PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
19if sys.version_info < (3, 8):
20 try:
21 from typing_extensions import Protocol
22 except ImportError: # pragma: no cover
23 Protocol = object
24else:
25 from typing import Protocol # noqa: F401
28class _AnnotationExtractor:
29 """
30 Extract type annotations from a callable, returning None whenever there
31 is none.
32 """
34 __slots__ = ["sig"]
36 def __init__(self, callable):
37 try:
38 self.sig = inspect.signature(callable)
39 except (ValueError, TypeError): # inspect failed
40 self.sig = None
42 def get_first_param_type(self):
43 """
44 Return the type annotation of the first argument if it's not empty.
45 """
46 if not self.sig:
47 return None
49 params = list(self.sig.parameters.values())
50 if params and params[0].annotation is not inspect.Parameter.empty:
51 return params[0].annotation
53 return None
55 def get_return_type(self):
56 """
57 Return the return type if it's not empty.
58 """
59 if (
60 self.sig
61 and self.sig.return_annotation is not inspect.Signature.empty
62 ):
63 return self.sig.return_annotation
65 return None
68# Thread-local global to track attrs instances which are already being repr'd.
69# This is needed because there is no other (thread-safe) way to pass info
70# about the instances that are already being repr'd through the call stack
71# in order to ensure we don't perform infinite recursion.
72#
73# For instance, if an instance contains a dict which contains that instance,
74# we need to know that we're already repr'ing the outside instance from within
75# the dict's repr() call.
76#
77# This lives here rather than in _make.py so that the functions in _make.py
78# don't have a direct reference to the thread-local in their globals dict.
79# If they have such a reference, it breaks cloudpickle.
80repr_context = threading.local()
83def get_generic_base(cl):
84 """If this is a generic class (A[str]), return the generic base for it."""
85 if cl.__class__ is _GenericAlias:
86 return cl.__origin__
87 return None