Skip to main content
Glama

propublica-mcp

typing_objects.py•16.9 kB
"""Low-level introspection utilities for [`typing`][] members. The provided functions in this module check against both the [`typing`][] and [`typing_extensions`][] variants, if they exists and are different. """ # ruff: noqa: UP006 import collections.abc import contextlib import re import sys import typing import warnings from textwrap import dedent from types import FunctionType, GenericAlias from typing import Any, Final import typing_extensions from typing_extensions import LiteralString, TypeAliasType, TypeIs, deprecated __all__ = ( 'DEPRECATED_ALIASES', 'NoneType', 'is_annotated', 'is_any', 'is_classvar', 'is_concatenate', 'is_deprecated', 'is_final', 'is_forwardref', 'is_generic', 'is_literal', 'is_literalstring', 'is_namedtuple', 'is_never', 'is_newtype', 'is_nodefault', 'is_noreturn', 'is_notrequired', 'is_paramspec', 'is_paramspecargs', 'is_paramspeckwargs', 'is_readonly', 'is_required', 'is_self', 'is_typealias', 'is_typealiastype', 'is_typeguard', 'is_typeis', 'is_typevar', 'is_typevartuple', 'is_union', 'is_unpack', ) _IS_PY310 = sys.version_info[:2] == (3, 10) def _compile_identity_check_function(member: LiteralString, function_name: LiteralString) -> FunctionType: """Create a function checking that the function argument is the (unparameterized) typing :paramref:`member`. The function will make sure to check against both the `typing` and `typing_extensions` variants as depending on the Python version, the `typing_extensions` variant might be different. For instance, on Python 3.9: ```pycon >>> from typing import Literal as t_Literal >>> from typing_extensions import Literal as te_Literal, get_origin >>> t_Literal is te_Literal False >>> get_origin(t_Literal[1]) typing.Literal >>> get_origin(te_Literal[1]) typing_extensions.Literal ``` """ in_typing = hasattr(typing, member) in_typing_extensions = hasattr(typing_extensions, member) if in_typing and in_typing_extensions: if getattr(typing, member) is getattr(typing_extensions, member): check_code = f'obj is typing.{member}' else: check_code = f'obj is typing.{member} or obj is typing_extensions.{member}' elif in_typing and not in_typing_extensions: check_code = f'obj is typing.{member}' elif not in_typing and in_typing_extensions: check_code = f'obj is typing_extensions.{member}' else: check_code = 'False' func_code = dedent(f""" def {function_name}(obj: Any, /) -> bool: return {check_code} """) locals_: dict[str, Any] = {} globals_: dict[str, Any] = {'Any': Any, 'typing': typing, 'typing_extensions': typing_extensions} exec(func_code, globals_, locals_) return locals_[function_name] def _compile_isinstance_check_function(member: LiteralString, function_name: LiteralString) -> FunctionType: """Create a function checking that the function is an instance of the typing `member`. The function will make sure to check against both the `typing` and `typing_extensions` variants as depending on the Python version, the `typing_extensions` variant might be different. """ in_typing = hasattr(typing, member) in_typing_extensions = hasattr(typing_extensions, member) if in_typing and in_typing_extensions: if getattr(typing, member) is getattr(typing_extensions, member): check_code = f'isinstance(obj, typing.{member})' else: check_code = f'isinstance(obj, (typing.{member}, typing_extensions.{member}))' elif in_typing and not in_typing_extensions: check_code = f'isinstance(obj, typing.{member})' elif not in_typing and in_typing_extensions: check_code = f'isinstance(obj, typing_extensions.{member})' else: check_code = 'False' func_code = dedent(f""" def {function_name}(obj: Any, /) -> 'TypeIs[{member}]': return {check_code} """) locals_: dict[str, Any] = {} globals_: dict[str, Any] = {'Any': Any, 'typing': typing, 'typing_extensions': typing_extensions} exec(func_code, globals_, locals_) return locals_[function_name] if sys.version_info >= (3, 10): from types import NoneType else: NoneType = type(None) # Keep this ordered, as per `typing.__all__`: is_annotated = _compile_identity_check_function('Annotated', 'is_annotated') is_annotated.__doc__ = """ Return whether the argument is the [`Annotated`][typing.Annotated] [special form][]. ```pycon >>> is_annotated(Annotated) True >>> is_annotated(Annotated[int, ...]) False ``` """ is_any = _compile_identity_check_function('Any', 'is_any') is_any.__doc__ = """ Return whether the argument is the [`Any`][typing.Any] [special form][]. ```pycon >>> is_any(Any) True ``` """ is_classvar = _compile_identity_check_function('ClassVar', 'is_classvar') is_classvar.__doc__ = """ Return whether the argument is the [`ClassVar`][typing.ClassVar] [type qualifier][]. ```pycon >>> is_classvar(ClassVar) True >>> is_classvar(ClassVar[int]) >>> False ``` """ is_concatenate = _compile_identity_check_function('Concatenate', 'is_concatenate') is_concatenate.__doc__ = """ Return whether the argument is the [`Concatenate`][typing.Concatenate] [special form][]. ```pycon >>> is_concatenate(Concatenate) True >>> is_concatenate(Concatenate[int, P]) False ``` """ is_final = _compile_identity_check_function('Final', 'is_final') is_final.__doc__ = """ Return whether the argument is the [`Final`][typing.Final] [type qualifier][]. ```pycon >>> is_final(Final) True >>> is_final(Final[int]) False ``` """ # Unlikely to have a different version in `typing-extensions`, but keep it consistent. # Also note that starting in 3.14, this is an alias to `annotationlib.ForwardRef`, but # accessing it from `typing` doesn't seem to be deprecated. is_forwardref = _compile_isinstance_check_function('ForwardRef', 'is_forwardref') is_forwardref.__doc__ = """ Return whether the argument is an instance of [`ForwardRef`][typing.ForwardRef]. ```pycon >>> is_forwardref(ForwardRef('T')) True ``` """ is_generic = _compile_identity_check_function('Generic', 'is_generic') is_generic.__doc__ = """ Return whether the argument is the [`Generic`][typing.Generic] [special form][]. ```pycon >>> is_generic(Generic) True >>> is_generic(Generic[T]) False ``` """ is_literal = _compile_identity_check_function('Literal', 'is_literal') is_literal.__doc__ = """ Return whether the argument is the [`Literal`][typing.Literal] [special form][]. ```pycon >>> is_literal(Literal) True >>> is_literal(Literal["a"]) False ``` """ # `get_origin(Optional[int]) is Union`, so `is_optional()` isn't implemented. is_paramspec = _compile_isinstance_check_function('ParamSpec', 'is_paramspec') is_paramspec.__doc__ = """ Return whether the argument is an instance of [`ParamSpec`][typing.ParamSpec]. ```pycon >>> P = ParamSpec('P') >>> is_paramspec(P) True ``` """ # Protocol? is_typevar = _compile_isinstance_check_function('TypeVar', 'is_typevar') is_typevar.__doc__ = """ Return whether the argument is an instance of [`TypeVar`][typing.TypeVar]. ```pycon >>> T = TypeVar('T') >>> is_typevar(T) True ``` """ is_typevartuple = _compile_isinstance_check_function('TypeVarTuple', 'is_typevartuple') is_typevartuple.__doc__ = """ Return whether the argument is an instance of [`TypeVarTuple`][typing.TypeVarTuple]. ```pycon >>> Ts = TypeVarTuple('Ts') >>> is_typevartuple(Ts) True ``` """ is_union = _compile_identity_check_function('Union', 'is_union') is_union.__doc__ = """ Return whether the argument is the [`Union`][typing.Union] [special form][]. This function can also be used to check for the [`Optional`][typing.Optional] [special form][], as at runtime, `Optional[int]` is equivalent to `Union[int, None]`. ```pycon >>> is_union(Union) True >>> is_union(Union[int, str]) False ``` !!! warning This does not check for unions using the [new syntax][types-union] (e.g. `int | str`). """ def is_namedtuple(obj: Any, /) -> bool: """Return whether the argument is a named tuple type. This includes [`NamedTuple`][typing.NamedTuple] subclasses and classes created from the [`collections.namedtuple`][] factory function. ```pycon >>> class User(NamedTuple): ... name: str ... >>> is_namedtuple(User) True >>> City = collections.namedtuple('City', []) >>> is_namedtuple(City) True >>> is_namedtuple(NamedTuple) False ``` """ return isinstance(obj, type) and issubclass(obj, tuple) and hasattr(obj, '_fields') # pyright: ignore[reportUnknownArgumentType] # TypedDict? # BinaryIO? IO? TextIO? is_literalstring = _compile_identity_check_function('LiteralString', 'is_literalstring') is_literalstring.__doc__ = """ Return whether the argument is the [`LiteralString`][typing.LiteralString] [special form][]. ```pycon >>> is_literalstring(LiteralString) True ``` """ is_never = _compile_identity_check_function('Never', 'is_never') is_never.__doc__ = """ Return whether the argument is the [`Never`][typing.Never] [special form][]. ```pycon >>> is_never(Never) True ``` """ if sys.version_info >= (3, 10): is_newtype = _compile_isinstance_check_function('NewType', 'is_newtype') else: # On Python 3.10, `NewType` is a function. def is_newtype(obj: Any, /) -> bool: return hasattr(obj, '__supertype__') is_newtype.__doc__ = """ Return whether the argument is a [`NewType`][typing.NewType]. ```pycon >>> UserId = NewType("UserId", int) >>> is_newtype(UserId) True ``` """ is_nodefault = _compile_identity_check_function('NoDefault', 'is_nodefault') is_nodefault.__doc__ = """ Return whether the argument is the [`NoDefault`][typing.NoDefault] sentinel object. ```pycon >>> is_nodefault(NoDefault) True ``` """ is_noreturn = _compile_identity_check_function('NoReturn', 'is_noreturn') is_noreturn.__doc__ = """ Return whether the argument is the [`NoReturn`][typing.NoReturn] [special form][]. ```pycon >>> is_noreturn(NoReturn) True >>> is_noreturn(Never) False ``` """ is_notrequired = _compile_identity_check_function('NotRequired', 'is_notrequired') is_notrequired.__doc__ = """ Return whether the argument is the [`NotRequired`][typing.NotRequired] [special form][]. ```pycon >>> is_notrequired(NotRequired) True ``` """ is_paramspecargs = _compile_isinstance_check_function('ParamSpecArgs', 'is_paramspecargs') is_paramspecargs.__doc__ = """ Return whether the argument is an instance of [`ParamSpecArgs`][typing.ParamSpecArgs]. ```pycon >>> P = ParamSpec('P') >>> is_paramspecargs(P.args) True ``` """ is_paramspeckwargs = _compile_isinstance_check_function('ParamSpecKwargs', 'is_paramspeckwargs') is_paramspeckwargs.__doc__ = """ Return whether the argument is an instance of [`ParamSpecKwargs`][typing.ParamSpecKwargs]. ```pycon >>> P = ParamSpec('P') >>> is_paramspeckwargs(P.kwargs) True ``` """ is_readonly = _compile_identity_check_function('ReadOnly', 'is_readonly') is_readonly.__doc__ = """ Return whether the argument is the [`ReadOnly`][typing.ReadOnly] [special form][]. ```pycon >>> is_readonly(ReadOnly) True ``` """ is_required = _compile_identity_check_function('Required', 'is_required') is_required.__doc__ = """ Return whether the argument is the [`Required`][typing.Required] [special form][]. ```pycon >>> is_required(Required) True ``` """ is_self = _compile_identity_check_function('Self', 'is_self') is_self.__doc__ = """ Return whether the argument is the [`Self`][typing.Self] [special form][]. ```pycon >>> is_self(Self) True ``` """ # TYPE_CHECKING? is_typealias = _compile_identity_check_function('TypeAlias', 'is_typealias') is_typealias.__doc__ = """ Return whether the argument is the [`TypeAlias`][typing.TypeAlias] [special form][]. ```pycon >>> is_typealias(TypeAlias) True ``` """ is_typeguard = _compile_identity_check_function('TypeGuard', 'is_typeguard') is_typeguard.__doc__ = """ Return whether the argument is the [`TypeGuard`][typing.TypeGuard] [special form][]. ```pycon >>> is_typeguard(TypeGuard) True ``` """ is_typeis = _compile_identity_check_function('TypeIs', 'is_typeis') is_typeis.__doc__ = """ Return whether the argument is the [`TypeIs`][typing.TypeIs] [special form][]. ```pycon >>> is_typeis(TypeIs) True ``` """ _is_typealiastype_inner = _compile_isinstance_check_function('TypeAliasType', '_is_typealiastype_inner') if _IS_PY310: # Parameterized PEP 695 type aliases are instances of `types.GenericAlias` in typing_extensions>=4.13.0. # On Python 3.10, with `Alias[int]` being such an instance of `GenericAlias`, # `isinstance(Alias[int], TypeAliasType)` returns `True`. # See https://github.com/python/cpython/issues/89828. def is_typealiastype(obj: Any, /) -> 'TypeIs[TypeAliasType]': return type(obj) is not GenericAlias and _is_typealiastype_inner(obj) else: is_typealiastype = _compile_isinstance_check_function('TypeAliasType', 'is_typealiastype') is_typealiastype.__doc__ = """ Return whether the argument is a [`TypeAliasType`][typing.TypeAliasType] instance. ```pycon >>> type MyInt = int >>> is_typealiastype(MyInt) True >>> MyStr = TypeAliasType("MyStr", str) >>> is_typealiastype(MyStr): True >>> type MyList[T] = list[T] >>> is_typealiastype(MyList[int]) False ``` """ is_unpack = _compile_identity_check_function('Unpack', 'is_unpack') is_unpack.__doc__ = """ Return whether the argument is the [`Unpack`][typing.Unpack] [special form][]. ```pycon >>> is_unpack(Unpack) True >>> is_unpack(Unpack[Ts]) False ``` """ if sys.version_info >= (3, 13): def is_deprecated(obj: Any, /) -> 'TypeIs[deprecated]': return isinstance(obj, (warnings.deprecated, typing_extensions.deprecated)) else: def is_deprecated(obj: Any, /) -> 'TypeIs[deprecated]': return isinstance(obj, typing_extensions.deprecated) is_deprecated.__doc__ = """ Return whether the argument is a [`deprecated`][warnings.deprecated] instance. This also includes the [`typing_extensions` backport][typing_extensions.deprecated]. ```pycon >>> is_deprecated(warnings.deprecated('message')) True >>> is_deprecated(typing_extensions.deprecated('message')) True ``` """ # Aliases defined in the `typing` module using `typing._SpecialGenericAlias` (itself aliased as `alias()`): DEPRECATED_ALIASES: Final[dict[Any, type[Any]]] = { typing.Hashable: collections.abc.Hashable, typing.Awaitable: collections.abc.Awaitable, typing.Coroutine: collections.abc.Coroutine, typing.AsyncIterable: collections.abc.AsyncIterable, typing.AsyncIterator: collections.abc.AsyncIterator, typing.Iterable: collections.abc.Iterable, typing.Iterator: collections.abc.Iterator, typing.Reversible: collections.abc.Reversible, typing.Sized: collections.abc.Sized, typing.Container: collections.abc.Container, typing.Collection: collections.abc.Collection, # type ignore reason: https://github.com/python/typeshed/issues/6257: typing.Callable: collections.abc.Callable, # pyright: ignore[reportAssignmentType, reportUnknownMemberType] typing.AbstractSet: collections.abc.Set, typing.MutableSet: collections.abc.MutableSet, typing.Mapping: collections.abc.Mapping, typing.MutableMapping: collections.abc.MutableMapping, typing.Sequence: collections.abc.Sequence, typing.MutableSequence: collections.abc.MutableSequence, typing.Tuple: tuple, typing.List: list, typing.Deque: collections.deque, typing.Set: set, typing.FrozenSet: frozenset, typing.MappingView: collections.abc.MappingView, typing.KeysView: collections.abc.KeysView, typing.ItemsView: collections.abc.ItemsView, typing.ValuesView: collections.abc.ValuesView, typing.Dict: dict, typing.DefaultDict: collections.defaultdict, typing.OrderedDict: collections.OrderedDict, typing.Counter: collections.Counter, typing.ChainMap: collections.ChainMap, typing.Generator: collections.abc.Generator, typing.AsyncGenerator: collections.abc.AsyncGenerator, typing.Type: type, # Defined in `typing.__getattr__`: typing.Pattern: re.Pattern, typing.Match: re.Match, typing.ContextManager: contextlib.AbstractContextManager, typing.AsyncContextManager: contextlib.AbstractAsyncContextManager, # Skipped: `ByteString` (deprecated, removed in 3.14) } """A mapping between the deprecated typing aliases to their replacement, as per [PEP 585](https://peps.python.org/pep-0585/).""" # Add the `typing_extensions` aliases: for alias, target in list(DEPRECATED_ALIASES.items()): # Use `alias.__name__` when we drop support for Python 3.9 if (te_alias := getattr(typing_extensions, alias._name, None)) is not None: DEPRECATED_ALIASES[te_alias] = target

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/asachs01/propublica-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server