55import ast
66import builtins
77import contextlib
8- import enum
98import inspect
109import re
1110import sys
1211import types
1312import typing
1413from collections .abc import Mapping
14+ from enum import Enum
1515from functools import cached_property , partial , partialmethod , singledispatchmethod
1616from importlib import import_module
1717from inspect import Parameter , Signature
2626if TYPE_CHECKING :
2727 from collections .abc import Callable , Sequence
2828 from inspect import _ParameterKind
29- from types import MethodType , ModuleType
30- from typing import Final
29+ from typing import Final , Protocol , Union
30+
31+ from typing_extensions import TypeGuard
32+
33+ class _SupportsGet (Protocol ):
34+ def __get__ (self , __instance : Any , __owner : type | None = ...) -> Any : ... # NoQA: E704
35+
36+ class _SupportsSet (Protocol ):
37+ # instance and value are contravariants but we do not need that precision
38+ def __set__ (self , __instance : Any , __value : Any ) -> None : ... # NoQA: E704
39+
40+ class _SupportsDelete (Protocol ):
41+ # instance is contravariant but we do not need that precision
42+ def __delete__ (self , __instance : Any ) -> None : ... # NoQA: E704
43+
44+ class _GenericAliasLike (Protocol ):
45+ # Minimalist interface for a generic alias in typing.py.
46+
47+ # The ``__origin__`` is defined both on the base type for generics
48+ # in typing.py *and* on the public ``types.GenericAlias`` type.
49+ __origin__ : type
50+
51+ # Note that special generic alias types (tuple and callables) do
52+ # not directly define ``__args__``. At runtime, however, they are
53+ # actually instances of ``typing._GenericAlias`` which does have
54+ # an ``__args__`` field.
55+ __args__ : tuple [Any , ...]
56+
57+ _RoutineType = Union [
58+ types .FunctionType ,
59+ types .LambdaType ,
60+ types .MethodType ,
61+ types .BuiltinFunctionType ,
62+ types .BuiltinMethodType ,
63+ types .WrapperDescriptorType ,
64+ types .MethodDescriptorType ,
65+ types .ClassMethodDescriptorType ,
66+ ]
3167
3268logger = logging .getLogger (__name__ )
3369
@@ -90,7 +126,7 @@ class methods and static methods.
90126
91127
92128def getall (obj : Any ) -> Sequence [str ] | None :
93- """Get the ``__all__`` attribute of an object as sequence.
129+ """Get the ``__all__`` attribute of an object as a sequence.
94130
95131 This returns ``None`` if the given ``obj.__all__`` does not exist and
96132 raises :exc:`ValueError` if ``obj.__all__`` is not a list or tuple of
@@ -184,14 +220,14 @@ def isNewType(obj: Any) -> bool:
184220 return __module__ == 'typing' and __qualname__ == 'NewType.<locals>.new_type'
185221
186222
187- def isenumclass (x : Any ) -> bool :
223+ def isenumclass (x : Any ) -> TypeGuard [ type [ Enum ]] :
188224 """Check if the object is an :class:`enumeration class <enum.Enum>`."""
189- return isclass (x ) and issubclass (x , enum . Enum )
225+ return isclass (x ) and issubclass (x , Enum )
190226
191227
192- def isenumattribute (x : Any ) -> bool :
228+ def isenumattribute (x : Any ) -> TypeGuard [ Enum ] :
193229 """Check if the object is an enumeration attribute."""
194- return isinstance (x , enum . Enum )
230+ return isinstance (x , Enum )
195231
196232
197233def unpartial (obj : Any ) -> Any :
@@ -206,7 +242,7 @@ def unpartial(obj: Any) -> Any:
206242 return obj
207243
208244
209- def ispartial (obj : Any ) -> bool :
245+ def ispartial (obj : Any ) -> TypeGuard [ partial | partialmethod ] :
210246 """Check if the object is a partial function or method."""
211247 return isinstance (obj , (partial , partialmethod ))
212248
@@ -239,7 +275,7 @@ def isstaticmethod(obj: Any, cls: Any = None, name: str | None = None) -> bool:
239275 return False
240276
241277
242- def isdescriptor (x : Any ) -> bool :
278+ def isdescriptor (x : Any ) -> TypeGuard [ _SupportsGet | _SupportsSet | _SupportsDelete ] :
243279 """Check if the object is a :external+python:term:`descriptor`."""
244280 return any (
245281 callable (safe_getattr (x , item , None )) for item in ('__get__' , '__set__' , '__delete__' )
@@ -251,7 +287,7 @@ def isabstractmethod(obj: Any) -> bool:
251287 return safe_getattr (obj , '__isabstractmethod__' , False ) is True
252288
253289
254- def isboundmethod (method : MethodType ) -> bool :
290+ def isboundmethod (method : types . MethodType ) -> bool :
255291 """Check if the method is a bound method."""
256292 return safe_getattr (method , '__self__' , None ) is not None
257293
@@ -306,12 +342,12 @@ def is_singledispatch_function(obj: Any) -> bool:
306342 )
307343
308344
309- def is_singledispatch_method (obj : Any ) -> bool :
345+ def is_singledispatch_method (obj : Any ) -> TypeGuard [ singledispatchmethod ] :
310346 """Check if the object is a :class:`~functools.singledispatchmethod`."""
311347 return isinstance (obj , singledispatchmethod )
312348
313349
314- def isfunction (obj : Any ) -> bool :
350+ def isfunction (obj : Any ) -> TypeGuard [ types . FunctionType ] :
315351 """Check if the object is a user-defined function.
316352
317353 Partial objects are unwrapped before checking them.
@@ -321,7 +357,7 @@ def isfunction(obj: Any) -> bool:
321357 return inspect .isfunction (unpartial (obj ))
322358
323359
324- def isbuiltin (obj : Any ) -> bool :
360+ def isbuiltin (obj : Any ) -> TypeGuard [ types . BuiltinFunctionType ] :
325361 """Check if the object is a built-in function or method.
326362
327363 Partial objects are unwrapped before checking them.
@@ -331,7 +367,7 @@ def isbuiltin(obj: Any) -> bool:
331367 return inspect .isbuiltin (unpartial (obj ))
332368
333369
334- def isroutine (obj : Any ) -> bool :
370+ def isroutine (obj : Any ) -> TypeGuard [ _RoutineType ] :
335371 """Check if the object is a kind of function or method.
336372
337373 Partial objects are unwrapped before checking them.
@@ -356,7 +392,7 @@ def _is_wrapped_coroutine(obj: Any) -> bool:
356392 return hasattr (obj , '__wrapped__' )
357393
358394
359- def isproperty (obj : Any ) -> bool :
395+ def isproperty (obj : Any ) -> TypeGuard [ property | cached_property ] :
360396 """Check if the object is property (possibly cached)."""
361397 return isinstance (obj , (property , cached_property ))
362398
@@ -431,8 +467,8 @@ def object_description(obj: Any, *, _seen: frozenset[int] = frozenset()) -> str:
431467 return 'frozenset({%s})' % ', ' .join (
432468 object_description (x , _seen = seen ) for x in sorted_values
433469 )
434- elif isinstance (obj , enum . Enum ):
435- if obj .__repr__ .__func__ is not enum . Enum .__repr__ : # type: ignore[attr-defined]
470+ elif isinstance (obj , Enum ):
471+ if obj .__repr__ .__func__ is not Enum .__repr__ : # type: ignore[attr-defined]
436472 return repr (obj )
437473 return f'{ obj .__class__ .__name__ } .{ obj .name } '
438474 elif isinstance (obj , tuple ):
@@ -527,7 +563,7 @@ def __init__(self, modname: str, mapping: Mapping[str, str]) -> None:
527563 self .__modname = modname
528564 self .__mapping = mapping
529565
530- self .__module : ModuleType | None = None
566+ self .__module : types . ModuleType | None = None
531567
532568 def __getattr__ (self , name : str ) -> Any :
533569 fullname = '.' .join (filter (None , [self .__modname , name ]))
0 commit comments