def test_basics(self): class Node(Generic[T]): def __init__(self, label: T): self.label = label self.left = self.right = None def add_both(self, left: "Optional[Node[T]]", right: "Node[T]" = None, stuff: int = None, blah=None): self.left = left self.right = right def add_left(self, node: Optional["Node[T]"]): self.add_both(node, None) def add_right(self, node: "Node[T]" = None): self.add_both(None, node) t = Node[int] both_hints = get_type_hints(t.add_both, globals(), locals()) self.assertEqual(both_hints["left"], Optional[Node[T]]) self.assertEqual(both_hints["right"], Optional[Node[T]]) self.assertEqual(both_hints["left"], both_hints["right"]) self.assertEqual(both_hints["stuff"], Optional[int]) self.assertNotIn("blah", both_hints) left_hints = get_type_hints(t.add_left, globals(), locals()) self.assertEqual(left_hints["node"], Optional[Node[T]]) right_hints = get_type_hints(t.add_right, globals(), locals()) self.assertEqual(right_hints["node"], Optional[Node[T]])
def test_basics(self): class Node(Generic[T]): def __init__(self, label: T): self.label = label self.left = self.right = None def add_both(self, left: 'Optional[Node[T]]', right: 'Node[T]' = None, stuff: int = None, blah=None): self.left = left self.right = right def add_left(self, node: Optional['Node[T]']): self.add_both(node, None) def add_right(self, node: 'Node[T]' = None): self.add_both(None, node) t = Node[int] both_hints = get_type_hints(t.add_both, globals(), locals()) self.assertEqual(both_hints['left'], Optional[Node[T]]) self.assertEqual(both_hints['right'], Optional[Node[T]]) self.assertEqual(both_hints['left'], both_hints['right']) self.assertEqual(both_hints['stuff'], Optional[int]) self.assertNotIn('blah', both_hints) left_hints = get_type_hints(t.add_left, globals(), locals()) self.assertEqual(left_hints['node'], Optional[Node[T]]) right_hints = get_type_hints(t.add_right, globals(), locals()) self.assertEqual(right_hints['node'], Optional[Node[T]])
def test_delayed_syntax_error(self): def foo(a: 'Node[T'): pass with self.assertRaises(SyntaxError): get_type_hints(foo)
def test_basics(self): class Node(Generic[T]): def __init__(self, label: T): self.label = label self.left = self.right = None def add_both(self, left: 'Optional[Node[T]]', right: 'Node[T]' = None, stuff: int = None, blah=None): self.left = left self.right = right def add_left(self, node: Optional['Node[T]']): self.add_both(node, None) def add_right(self, node: 'Node[T]' = None): self.add_both(None, node) t = Node[int] both_hints = get_type_hints(t.add_both, globals(), locals()) assert both_hints['left'] == both_hints['right'] == Optional[Node[T]] assert both_hints['stuff'] == Optional[int] assert 'blah' not in both_hints left_hints = get_type_hints(t.add_left, globals(), locals()) assert left_hints['node'] == Optional[Node[T]] right_hints = get_type_hints(t.add_right, globals(), locals()) assert right_hints['node'] == Optional[Node[T]]
def test_name_error(self): def foo(a: 'Noode[T]'): pass with self.assertRaises(NameError): get_type_hints(foo, locals())
def test_type_error(self): def foo(a: Tuple['42']): pass with self.assertRaises(TypeError): get_type_hints(foo)
def test_basics(self): class Node(Generic[T]): def __init__(self, label: T): self.label = label self.left = self.right = None def add_both(self, left: "Optional[Node[T]]", right: "Node[T]" = None, stuff: int = None, blah=None): self.left = left self.right = right def add_left(self, node: Optional["Node[T]"]): self.add_both(node, None) def add_right(self, node: "Node[T]" = None): self.add_both(None, node) t = Node[int] both_hints = get_type_hints(t.add_both, globals(), locals()) assert both_hints["left"] == both_hints["right"] == Optional[Node[T]] assert both_hints["stuff"] == Optional[int] assert "blah" not in both_hints left_hints = get_type_hints(t.add_left, globals(), locals()) assert left_hints["node"] == Optional[Node[T]] right_hints = get_type_hints(t.add_right, globals(), locals()) assert right_hints["node"] == Optional[Node[T]]
def test_generics_replacement(self): """ Most basic change. Confirm that generic parameters are actually swapped out on child classes. """ Domain = hktyping.HKTypeVar('Domain') Codomain = hktyping.HKTypeVar('Codomain') class Functor(hktyping.HKGeneric[Domain, Codomain]): def fmap_like(self, function: Domain) -> Codomain: pass class ListFunctor(Functor[AnyCategory, ListCategory]): pass listf = ListFunctor() self.assertEqual(Functor.__parameters__, (Domain, Codomain)) self.assertEqual(ListFunctor.__parameters__, (AnyCategory, ListCategory)) self.assertEqual(listf.__parameters__, (AnyCategory, ListCategory)) # # THIS IS BAD - AND I SHOULD FEEL BAD # It looks like the replacement is occuring to the parent, which is terrible # self.assertNotEqual( typing.get_type_hints(Functor.fmap_like), {'function': Domain, 'return': Codomain}) # These are correct self.assertEqual( typing.get_type_hints(ListFunctor.fmap_like), {'function': AnyCategory, 'return': ListCategory}) self.assertEqual( typing.get_type_hints(listf.fmap_like), {'function': AnyCategory, 'return': ListCategory})
def test_standard_generics(self): Domain = typing.TypeVar('Domain') Codomain = typing.TypeVar('Codomain') class Functor(typing.Generic[Domain, Codomain]): def fmap_like(self, function: Domain) -> Codomain: pass class ListFunctor(Functor[AnyCategory, ListCategory]): pass listf = ListFunctor() self.assertEqual(Functor.__parameters__, (Domain, Codomain)) self.assertEqual(ListFunctor.__parameters__, (AnyCategory, ListCategory)) self.assertEqual(listf.__parameters__, (AnyCategory, ListCategory)) self.assertEqual( typing.get_type_hints(Functor.fmap_like), {'function': Domain, 'return': Codomain}) # This is bad behavior - the __annotations__ on methods on our child class & instances # does not reflect the changes to __parameters__ # However, this is the default behavior of typing, so I'm testing for it self.assertEqual( typing.get_type_hints(ListFunctor.fmap_like), {'function': Domain, 'return': Codomain}) self.assertEqual( typing.get_type_hints(listf.fmap_like), {'function': Domain, 'return': Codomain})
def test_no_type_check_class(self): @no_type_check class C: def foo(a: "whatevers") -> {}: pass cth = get_type_hints(C.foo) self.assertEqual(cth, {}) ith = get_type_hints(C().foo) self.assertEqual(ith, {})
def generate_new_enforcer(func, generic, parent_root, instance_of, settings): """ Private function for generating new Enforcer instances for the incoming function """ if parent_root is not None: if type(parent_root) is not Validator: raise TypeError('Parent validator must be a Validator') if instance_of is not None: if type(instance_of) is not GenericProxy: raise TypeError('Instance of a generic must be derived from a valid Generic Proxy') if generic: hints = OrderedDict() if instance_of: func = instance_of func_type = type(func) has_origin = func.__origin__ is not None # Collects generic's parameters - TypeVar-s specified on itself or on origin (if constrained) if not func.__parameters__ and (not has_origin or not func.__origin__.__parameters__): raise TypeError('User defined generic is invalid') parameters = func.__parameters__ if func.__parameters__ else func.__origin__.__parameters__ # Maps parameter names to parameters, while preserving the order of their definition for param in parameters: hints[param.__name__] = EnhancedTypeVar(param.__name__, type_var=param) # Verifies that constraints do not contradict generic's parameter definition # and bounds parameters to constraints (if constrained) bound = bool(func.__args__) if bound: for i, param in enumerate(hints.values()): arg = func.__args__[i] if is_type_of_type(arg, param): param.__bound__ = arg else: raise TypeError('User defined generic does not accept provided constraints') # NOTE: # Signature in generics should always point to the original unconstrained generic # This applies even to the instances of such Generics if has_origin: signature = func.__origin__ else: signature = func.__wrapped__ if func_type is GenericProxy else func validator = init_validator(hints, parent_root) else: bound = False signature = inspect.signature(func) hints = typing.get_type_hints(func) validator = init_validator(hints, parent_root) return Enforcer(validator, signature, hints, generic, bound, settings)
def fields(self) -> Dict[str, _Field]: def make_factory(value: object) -> Callable[[], Any]: return lambda: value if self._fields is None: hints = typing.get_type_hints(self.type) # This is gnarly. Sorry. For each field, store its default_factory if present; otherwise # create a factory returning its default if present; otherwise None. Default parameter # in the lambda is a ~~hack~~ to avoid messing up the variable binding. fields: Dict[str, _Field] = { field.name: _Field( field.default_factory # type: ignore if field.default_factory is not MISSING # type: ignore else ( (make_factory(field.default)) if field.default is not MISSING else None ), hints[field.name], ) for field in dataclasses.fields(self.type) } self._fields = fields return self._fields
def test_get_type_hints_dummy(self): def foo(x): # type: (int) -> int return x + 1 self.assertIsNone(typing.get_type_hints(foo))
def register(cls, func=None): """generic_func.register(cls, func) -> func Registers a new implementation for the given *cls* on a *generic_func*. """ nonlocal cache_token if func is None: if isinstance(cls, type): return lambda f: register(cls, f) ann = getattr(cls, '__annotations__', {}) if not ann: raise TypeError( f"Invalid first argument to `register()`: {cls!r}. " f"Use either `@register(some_class)` or plain `@register` " f"on an annotated function." ) func = cls # only import typing if annotation parsing is necessary from typing import get_type_hints argname, cls = next(iter(get_type_hints(func).items())) assert isinstance(cls, type), ( f"Invalid annotation for {argname!r}. {cls!r} is not a class." ) registry[cls] = func if cache_token is None and hasattr(cls, '__abstractmethods__'): cache_token = get_cache_token() dispatch_cache.clear() return func
def polymorphic(func): global _registry func_key = func.__module__ + '.' + func.__qualname__ parameters = signature(func).parameters parameters_tuple = tuple(parameters.values()) if func_key not in _registry: def dispatcher(*args, **kwargs): return _call_func(func_key, args, kwargs) dispatcher = update_dispatcher(dispatcher, func, assign=True) signature_mapping = OrderedDict() signature_mapping[parameters_tuple] = func signature_mapping.dispatcher = dispatcher _registry[func_key] = signature_mapping return dispatcher elif parameters_tuple not in _registry[func_key]: _registry[func_key][parameters_tuple] = func dispatcher = _registry[func_key].dispatcher return update_dispatcher(dispatcher, func, assign=False) else: hints = get_type_hints(func) sig_gen = ( '{}:{}'.format(p, hints[p]) if p in hints else p for p in parameters ) raise PolypieException( "Function '{func}' with signature ({sig}) " "already exists".format(func=func_key, sig=', '.join(sig_gen)) )
def wrap_fun(fun: T, injector: Injector) -> T: if isinstance(fun, LocalProxy): return fun # type: ignore if ismethod(fun): fun = instance_method_wrapper(fun) # Important: this block needs to stay here so it's executed *before* the # hasattr(fun, '__call__') block below - otherwise things may crash. if hasattr(fun, '__bindings__'): return wrap_function(fun, injector) if hasattr(fun, '__call__') and not isinstance(fun, type): try: type_hints = get_type_hints(fun) except (AttributeError, TypeError): # Some callables aren't introspectable with get_type_hints, # let's assume they don't have anything to inject. The exception # types handled here are what I encountered so far. # It used to be AttributeError, then https://github.com/python/typing/pull/314 # changed it to TypeError. wrap_it = False except NameError: wrap_it = True else: type_hints.pop('return', None) wrap_it = type_hints != {} if wrap_it: return wrap_fun(inject(fun), injector) if hasattr(fun, 'view_class'): return wrap_class_based_view(fun, injector) return fun
def annotations_corrector(cls, method_name): """ Now... how to make this replace the __annotations__? Options (1) Look in the internals of typing.py (2) Run/replace on classes after construction (3) Somehow turn __annotations__ into a getter """ method = getattr(cls, method_name) annotations = typing.get_type_hints(method) accumulator = dict() for key, value in annotations.items(): # If it is an unfilled typevar if isinstance(value, typing.TypeVar): # Find parent with generic version of this parameter position = None for parent in cls.__mro__: if value in getattr(parent, '__parameters__', []): position = parent.__parameters__.index(value) if position is None: raise ValueError("Could not find position in __parameters__ of parent classes") concrete = cls.__parameters__[position] accumulator[key] = concrete else: accumulator[key] = value return accumulator
def test_no_type_check(self): @no_type_check def foo(a: "whatevers") -> {}: pass th = get_type_hints(foo) self.assertEqual(th, {})
def message(cls: Type[T]) -> Type[T]: """ Returns the same class as was passed in, with additional dunder attributes needed for serialization and deserialization. """ type_hints = get_type_hints(cls) try: # Used to list all fields and locate fields by field number. cls.__protobuf_fields__: Dict[int, Field] = dict( make_field(field_.metadata['number'], field_.name, type_hints[field_.name]) for field_ in dataclasses.fields(cls) ) except KeyError as e: # FIXME: catch `KeyError` in `make_field` and re-raise as `TypeError`. raise TypeError(f'type is not serializable: {e}') from e # noinspection PyUnresolvedReferences Message.register(cls) cls.serializer = MessageSerializer(cls) cls.type_url = f'type.googleapis.com/{cls.__module__}.{cls.__name__}' cls.validate = Message.validate cls.dump = Message.dump cls.dumps = Message.dumps cls.merge_from = Message.merge_from cls.load = classmethod(load) cls.loads = classmethod(loads) return cls
def delgator(pol_tr: PolTRSpec, method: typing.Callable): """ Helper function to delegate methods calls from PolTRSpec to the methods of TimeResSpec. Parameters ---------- pol_tr : PolTRSpec method : method of TimeResSpec The method to wrap. Uses function annotations to check if the method returns a new TimeResSpec. """ name = method.__name__ hints = typing.get_type_hints(method) if "return" in hints: do_return = hints["return"] == TimeResSpec else: do_return = False @functools.wraps(method) def func(*args, **kwargs): para = method(pol_tr.para, *args, **kwargs) perp = method(pol_tr.perp, *args, **kwargs) if do_return: return PolTRSpec(para, perp) func.__docs__ = method.__doc__ func.__name__ = name return func
def check_callable(callable_: typing.Callable, hint: type) -> bool: """Check argument type & return type of :class:`typing.Callable`. since it raises check :class:`typing.Callable` using `isinstance`, so compare in diffrent way :param callable_: callable object given as a argument :param hint: assumed type of given ``callable_`` """ if not callable(callable_): return type(callable_), False if callable(callable_) and not hasattr(callable_, '__code__'): return type(callable_), True hints = typing.get_type_hints(callable_) return_type = hints.pop('return', type(None)) signature = inspect.signature(callable_) arg_types = tuple( param.annotation for _, param in signature.parameters.items() ) correct = all({ any({ hint.__args__ is None, hint.__args__ is Ellipsis, hint.__args__ == arg_types, }), any({ hint.__result__ is None, hint.__result__ in (typing.Any, return_type) }) }) return typing.Callable[list(arg_types), return_type], correct
def get_signature(func): """ Gathers information about the call signature of `func`. """ code = func.__code__ # Names of regular parameters parameters = tuple(code.co_varnames[:code.co_argcount]) # Flags has_varargs = bool(code.co_flags & inspect.CO_VARARGS) has_varkw = bool(code.co_flags & inspect.CO_VARKEYWORDS) has_kwonly = bool(code.co_kwonlyargcount) # A mapping of parameter names to default values default_values = func.__defaults__ or () defaults = dict(zip(parameters[-len(default_values):], default_values)) # Type annotations for all parameters type_hints = typing.get_type_hints(func) if typing else func.__annotations__ types = tuple(normalize_type(type_hints.get(param, AnyType)) for param in parameters) # Type annotations for required parameters required = types[:-len(defaults)] if defaults else types # Complexity complexity = tuple(map(type_complexity, types)) if typing else None return Signature(parameters, types, complexity, defaults, required, has_varargs, has_varkw, has_kwonly)
def _annotations_corrector(function, bases, parameters): """ """ annotations = typing.get_type_hints(function) accumulator = dict() for key, value in annotations.items(): # If it is an unfilled typevar if isinstance(value, typing.TypeVar): # Find parent with generic version of this parameter position = None for parent in bases: if value in getattr(parent, '__parameters__', []): position = parent.__parameters__.index(value) if position is None: raise ValueError("Could not find position in __parameters__ of parent classes") # If this is a structured reference, resolve it if _is_structured_forward_ref(value): base = parameters[position] tinyns = {value._structured_forward_ref_name: parameters[position]} # my_lambda = "lambda {0}: {1}".format(value._structured_forward_ref_name, value._structured_forward_ref_code) concrete = eval(value._structured_forward_ref_code, tinyns) else: concrete = parameters[position] accumulator[key] = concrete else: accumulator[key] = value return accumulator
def test_callable_with_ellipsis_forward(self): def foo(a: 'Callable[..., T]'): pass self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': Callable[..., T]})
def test_union_forward(self): def foo(a: Union['T']): pass self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': Union[T]})
def test_tuple_forward(self): def foo(a: Tuple['T']): pass self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': Tuple[T]})
def test_callable_forward(self): def foo(a: Callable[['T'], 'T']): pass self.assertEqual(get_type_hints(foo, globals(), locals()), {'a': Callable[[T], T]})
def type_check(item, attr_name, value): th_cls = typing.get_type_hints(item) if hasattr(item, '__annotations__') else {} try: tt = th_cls[attr_name] except KeyError: th_init = typing.get_type_hints(item.__init__) try: tt = th_init[attr_name] except KeyError: return allowed = typing_inspect.get_args(tt) or tt if not isinstance(value, allowed): one_of = "with one of following types" if isinstance(allowed, tuple) else "of type" return "Expected value {one_of}: {exp}, got {got} for {cls}.{member}".format( one_of=one_of, exp=allowed, got=type(value), cls=item.__class__.__name__, member=attr_name) return None
def get_output_interface(func): return_type = get_type_hints(func).get('return') if return_type is None: return None # Unwrap iterators (used for geom shader output) origin = getattr(return_type, '__origin__', None) if origin is not None and origin == Iterator: return_type = return_type.__parameters__[0] return return_type
def test_default_globals(self): code = ("class C:\n" " def foo(self, a: 'C') -> 'D': pass\n" "class D:\n" " def bar(self, b: 'D') -> C: pass\n" ) ns = {} exec(code, ns) hints = get_type_hints(ns['C'].foo) assert hints == {'a': ns['C'], 'return': ns['D']}
def test_tuple_forward(self): def foo(a: Tuple['T']): pass self.assertEqual(get_type_hints(foo), {'a': Tuple[T]})
def test_typing_present(self): assert is_palindromic.__hints__ == typing.get_type_hints(self.is_palindromic_oracle) assert typing.get_type_hints (gen_palindromic) == typing.get_type_hints (self.gen_palindromic_oracle) assert typing.get_type_hints (represent) == typing.get_type_hints (self.represent_oracle)
def test_callable_forward(self): def foo(a: Callable[['T'], 'T']): pass self.assertEqual(get_type_hints(foo), {'a': Callable[[T], T]})
def test_slot_add_returntype(): def test(self, name: str) -> str: ... slot_kwargs = utils._slot_kwargs(get_type_hints(test)) assert slot_kwargs == {"result": str}
def __init__(self, dto_obj: dto.ReportItemMessageDto) -> None: super().__init__(dto_obj) self._obj = get_type_hints(self.__class__).get("_obj")( # type: ignore **dto_obj.payload)
def get_type_hints(thing): try: import typing return typing.get_type_hints(thing) except TypeError: return {}
def generate_inputs(cls): return { name: generate_for_type(typ) for name, typ in get_type_hints(cls.solution).items() }
def _fields(cls) -> dict[str, type]: return { name: py_type for name, py_type in get_type_hints(cls).items() if not name.startswith('_') }
def formatargspec(function, args, varargs=None, varkw=None, defaults=None, kwonlyargs=(), kwonlydefaults={}, annotations={}): # type: (Callable, Tuple[str, ...], str, str, Any, Tuple, Dict, Dict[str, Any]) -> str """Return a string representation of an ``inspect.FullArgSpec`` tuple. An enhanced version of ``inspect.formatargspec()`` that handles typing annotations better. """ warnings.warn('formatargspec() is now deprecated. ' 'Please use sphinx.util.inspect.Signature instead.', RemovedInSphinx20Warning) def format_arg_with_annotation(name): # type: (str) -> str if name in annotations: return '%s: %s' % (name, format_annotation(get_annotation(name))) return name def get_annotation(name): # type: (str) -> str value = annotations[name] if isinstance(value, string_types): return introspected_hints.get(name, value) else: return value introspected_hints = (typing.get_type_hints(function) # type: ignore if typing and hasattr(function, '__code__') else {}) fd = StringIO() fd.write('(') formatted = [] defaults_start = len(args) - len(defaults) if defaults else len(args) for i, arg in enumerate(args): arg_fd = StringIO() if isinstance(arg, list): # support tupled arguments list (only for py2): def foo((x, y)) arg_fd.write('(') arg_fd.write(format_arg_with_annotation(arg[0])) for param in arg[1:]: arg_fd.write(', ') arg_fd.write(format_arg_with_annotation(param)) arg_fd.write(')') else: arg_fd.write(format_arg_with_annotation(arg)) if defaults and i >= defaults_start: arg_fd.write(' = ' if arg in annotations else '=') arg_fd.write(object_description(defaults[i - defaults_start])) # type: ignore formatted.append(arg_fd.getvalue()) if varargs: formatted.append('*' + format_arg_with_annotation(varargs)) if kwonlyargs: if not varargs: formatted.append('*') for kwarg in kwonlyargs: arg_fd = StringIO() arg_fd.write(format_arg_with_annotation(kwarg)) if kwonlydefaults and kwarg in kwonlydefaults: arg_fd.write(' = ' if kwarg in annotations else '=') arg_fd.write(object_description(kwonlydefaults[kwarg])) # type: ignore formatted.append(arg_fd.getvalue()) if varkw: formatted.append('**' + format_arg_with_annotation(varkw)) fd.write(', '.join(formatted)) fd.write(')') if 'return' in annotations: fd.write(' -> ') fd.write(format_annotation(get_annotation('return'))) return fd.getvalue()
def test_typing_present(self): assert list_filter.__hints__ == typing.get_type_hints( self.list_filter_oracle)
比较简单, 需要先了解 typing 这个库 :param a: :param b: :param c: :return: """ pass XX = type('XX', (object, ), dict(a=1)) # 产生一个新的类型 XX print('------X和XX') print(X) print(XX) # <class '__main__.X'> # <class '__main__.X'> print('类型------X和XX类') print(type(X)) print(type(XX)) print('类型------实例化X和XX') print(type(X())) print(type(XX())) # type hint def type_func(param: str) -> str: pass print(typing.get_type_hints(X)) print(typing.get_type_hints(type_func))
"elements": ["Si", "O"], "exclude_elements": ["Si"], "possible_species": ["O2-"], "crystal_system": CrystalSystem.cubic, "spacegroup_number": 38, "spacegroup_symbol": "Amm2", "has_props": [HasProps.dielectric], "theoretical": True, "has_reconstructed": False, "magnetic_ordering": Ordering.FM, } # type: dict search_method = SummaryRester().search # Get list of parameters param_tuples = list(typing.get_type_hints(search_method).items()) # Query API for each numeric and boolean parameter and check if returned for entry in param_tuples: param = entry[0] if param not in excluded_params: param_type = entry[1].__args__[0] q = None if param in custom_field_tests: project_field = alt_name_dict.get(param, None) q = { param: custom_field_tests[param], "chunk_size": 1, "num_chunks": 1, }
def stream(self, f: BinaryIO) -> None: for f_name, f_type in get_type_hints(self).items(): # type: ignore self.stream_one_item(f_type, getattr(self, f_name), f)
def parse(cls: Type[cls.__name__], f: BinaryIO) -> cls.__name__: # type: ignore values = [] for _, f_type in get_type_hints(cls).items(): values.append(cls.parse_one_item(f_type, f)) # type: ignore return cls(*values)
def test_union_forward(self): def foo(a: Union['T']): pass self.assertEqual(get_type_hints(foo), {'a': Union[T]})
def iter_register_deps(cls): for value in typing.get_type_hints(cls, {}, {}).values(): dependency = get_dependency_from_annotation(value) if dependency is not None: yield dependency
def test_initialisation(): class Original: a: str = "a_default" b: str = None c: str assert get_type_hints(Original) == {"a": str, "b": str, "c": str} assert Original.a == "a_default" assert Original.b is None assert not hasattr(Original, "c") DecoratedOriginal = envvar_profile_cls(Original) assert issubclass(DecoratedOriginal, EnvvarProfile) assert DecoratedOriginal.profile_root == "original" assert DecoratedOriginal.profile_properties == ["a", "b", "c"] assert DecoratedOriginal.a == EnvvarProfileProperty("a", "a_default", str) assert DecoratedOriginal.b == EnvvarProfileProperty("b", None, str) assert DecoratedOriginal.c == EnvvarProfileProperty("c", None, str) class Derived(DecoratedOriginal): b: str = "b_default" d: str = None e: str assert Derived.profile_properties == ["a", "b", "c"] assert Derived.b == "b_default" assert Derived.d is None assert not hasattr(Derived, "e") DecoratedDerived = envvar_profile_cls(Derived) assert DecoratedDerived.profile_root == "derived" assert DecoratedDerived.profile_properties == ["a", "b", "c", "d", "e"] assert DecoratedDerived.a == EnvvarProfileProperty("a", "a_default", str) assert DecoratedDerived.b == EnvvarProfileProperty("b", "b_default", str) assert DecoratedDerived.c == EnvvarProfileProperty("c", None, str) assert DecoratedDerived.d == EnvvarProfileProperty("d", None, str) assert DecoratedDerived.e == EnvvarProfileProperty("e", None, str) assert isinstance(DecoratedDerived.c, EnvvarProfileProperty) assert DecoratedDerived.c.name == "c" assert DecoratedDerived.c.default is None assert DecoratedDerived.c.type_ is str assert isinstance(DecoratedDerived.a, EnvvarProfileProperty) assert DecoratedDerived.a.name == "a" assert DecoratedDerived.a.default == "a_default" assert DecoratedDerived.a.type_ is str class DoubleDerived(DecoratedDerived): f: str = None assert DoubleDerived.profile_properties == ["a", "b", "c", "d", "e"] DecoratedDoubleDerived = envvar_profile_cls(DoubleDerived) assert DecoratedDoubleDerived.profile_root == "double_derived" assert DecoratedDoubleDerived.profile_properties == [ "a", "b", "c", "d", "e", "f" ] assert DecoratedDoubleDerived.a == EnvvarProfileProperty( "a", "a_default", str) assert DecoratedDoubleDerived.b == EnvvarProfileProperty( "b", "b_default", str) assert DecoratedDoubleDerived.c == EnvvarProfileProperty("c", None, str) assert DecoratedDoubleDerived.d == EnvvarProfileProperty("d", None, str) assert DecoratedDoubleDerived.e == EnvvarProfileProperty("e", None, str) assert DecoratedDoubleDerived.f == EnvvarProfileProperty("f", None, str)
def test_typing_present(self): assert divisors.__hints__ == typing.get_type_hints( self.divisors_oracle)
def __set_name__(self, owner: Processor, name): types = typing.get_type_hints(self.fn) owner.handle_message.register(types['msg'], self.fn) setattr(owner, name, self.fn)
def return_type(func: FunctionType) -> str: value = get_type_hints(func, globals())["return"] return process_type(value)
def _get_needs_for_ctor(self, cls): try: return typing.get_type_hints(cls.__init__, None, self._localns) except NameError as e: raise InvalidForwardReferenceException(str(e))
def serialize_python_type(self, value: Any) -> str: str_value = str(value) if isinstance(value, list): return f"[{', '.join(list(map(lambda a: self.serialize_python_type(a), value)))}]" if str_value == "<class 'playwright._impl._types.Error'>": return "Error" match = re.match(r"^<class '((?:pathlib\.)?\w+)'>$", str_value) if match: return match.group(1) match = re.match( r"playwright._impl._event_context_manager.EventContextManagerImpl\[playwright._impl.[^.]+.(.*)\]", str_value, ) if match: return "EventContextManager[" + match.group(1) + "]" match = re.match(r"^<class 'playwright\._impl\.[\w_]+\.([^']+)'>$", str_value) if (match and "_api_structures" not in str_value and "_api_types" not in str_value): if match.group(1) == "EventContextManagerImpl": return "EventContextManager" return match.group(1) match = re.match(r"^typing\.(\w+)$", str_value) if match: return match.group(1) origin = get_origin(value) args = get_args(value) hints = None try: hints = get_type_hints(value) except Exception: pass if hints: signature: List[str] = [] for [name, value] in hints.items(): signature.append( f"{name}: {self.serialize_python_type(value)}") return f"{{{', '.join(signature)}}}" if origin == Union: args = get_args(value) if len(args) == 2 and str(args[1]) == "<class 'NoneType'>": return self.make_optional(self.serialize_python_type(args[0])) ll = list(map(lambda a: self.serialize_python_type(a), args)) ll.sort(key=lambda item: "}" if item == "NoneType" else item) return f"Union[{', '.join(ll)}]" if str(origin) == "<class 'dict'>": args = get_args(value) return f"Dict[{', '.join(list(map(lambda a: self.serialize_python_type(a), args)))}]" if str(origin) == "<class 'list'>": args = get_args(value) return f"List[{', '.join(list(map(lambda a: self.serialize_python_type(a), args)))}]" if str(origin) == "<class 'collections.abc.Callable'>": args = get_args(value) return f"Callable[{', '.join(list(map(lambda a: self.serialize_python_type(a), args)))}]" if str(origin) == "typing.Literal": args = get_args(value) if len(args) == 1: return '"' + self.serialize_python_type(args[0]) + '"' body = ", ".join( list( map(lambda a: '"' + self.serialize_python_type(a) + '"', args))) return f"Union[{body}]" return str_value
def test_slot_ignore_self(): def test(self, name: str): ... slot_args = utils._slot_args(test, get_type_hints(test)) assert slot_args == [str]
def __init__(self, func: Callable, frame_locals: Optional[Dict[str, Any]] = None, args: tuple = None, kwargs: Dict[str, Any] = None, forward_refs_policy=ForwardRefPolicy.ERROR): super().__init__(func.__globals__, frame_locals) self.func = func self.func_name = function_name(func) self.is_generator = isgeneratorfunction(func) signature = inspect.signature(func) if args is not None and kwargs is not None: self.arguments = signature.bind(*args, **kwargs).arguments else: assert frame_locals is not None, 'frame must be specified if args or kwargs is None' self.arguments = frame_locals self.type_hints = _type_hints_map.get(func) if self.type_hints is None: while True: if sys.version_info < (3, 5, 3): frame_locals = dict(frame_locals) try: hints = get_type_hints(func, localns=frame_locals) except NameError as exc: if forward_refs_policy is ForwardRefPolicy.ERROR: raise typename = str(exc).split("'", 2)[1] for param in signature.parameters.values(): if param.annotation == typename: break else: raise func_name = function_name(func) if forward_refs_policy is ForwardRefPolicy.GUESS: if param.name in self.arguments: argtype = self.arguments[param.name].__class__ if param.annotation == argtype.__qualname__: func.__annotations__[param.name] = argtype msg = ( 'Replaced forward declaration {!r} in {} with {!r}' .format(param.annotation, func_name, argtype)) warn(TypeHintWarning(msg)) continue msg = 'Could not resolve type hint {!r} on {}: {}'.format( param.annotation, function_name(func), exc) warn(TypeHintWarning(msg)) del func.__annotations__[param.name] else: break self.type_hints = OrderedDict() for name, parameter in signature.parameters.items(): if name in hints: annotated_type = hints[name] # PEP 428 discourages it by MyPy does not complain if parameter.default is None: annotated_type = Optional[annotated_type] if parameter.kind == Parameter.VAR_POSITIONAL: self.type_hints[name] = Tuple[annotated_type, ...] elif parameter.kind == Parameter.VAR_KEYWORD: self.type_hints[name] = Dict[str, annotated_type] else: self.type_hints[name] = annotated_type if 'return' in hints: self.type_hints['return'] = hints['return'] _type_hints_map[func] = self.type_hints
def _annotations(self): return get_type_hints(self)
def generate(t: Any) -> None: print("") class_name = short_name(t) base_class = t.__bases__[0].__name__ base_sync_class = ("AsyncBase" if base_class == "ChannelOwner" or base_class == "object" else base_class) print(f"class {class_name}({base_sync_class}):") print("") print(f" def __init__(self, obj: {class_name}Impl):") print(" super().__init__(obj)") for [name, type] in get_type_hints(t, api_globals).items(): print("") print(" @property") print(f" def {to_snake_case(name)}(self) -> {process_type(type)}:") documentation_provider.print_entry(class_name, to_snake_case(name), {"return": type}) [prefix, suffix] = return_value(type) prefix = " return " + prefix + f"self._impl_obj.{name}" print(f"{prefix}{suffix}") for [name, value] in t.__dict__.items(): if name.startswith("_"): continue if not name.startswith("_") and str(value).startswith("<property"): value = value.fget print("") print(" @property") print( f" def {to_snake_case(name)}({signature(value, len(name) + 9)}) -> {return_type(value)}:" ) documentation_provider.print_entry( class_name, to_snake_case(name), get_type_hints(value, api_globals)) [prefix, suffix ] = return_value(get_type_hints(value, api_globals)["return"]) prefix = " return " + prefix + f"self._impl_obj.{name}" print(f"{prefix}{arguments(value, len(prefix))}{suffix}") for [name, value] in t.__dict__.items(): if (not name.startswith("_") and isinstance(value, FunctionType) and "expect_" not in name and "remove_listener" != name): is_async = inspect.iscoroutinefunction(value) print("") async_prefix = "async " if is_async else "" await_prefix = "await " if is_async else "" print( f" {async_prefix}def {to_snake_case(name)}({signature(value, len(name) + 9)}) -> {return_type(value)}:" ) documentation_provider.print_entry( class_name, to_snake_case(name), get_type_hints(value, api_globals)) [prefix, suffix ] = return_value(get_type_hints(value, api_globals)["return"]) prefix = prefix + f"{await_prefix}self._impl_obj.{name}(" suffix = ")" + suffix print(f""" try: log_api("=> {to_snake_case(class_name)}.{to_snake_case(name)} started") result = {prefix}{arguments(value, len(prefix))}{suffix} log_api("<= {to_snake_case(class_name)}.{to_snake_case(name)} succeded") return result except Exception as e: log_api("<= {to_snake_case(class_name)}.{to_snake_case(name)} failed") raise e""") if "expect_" in name: print("") return_type_value = return_type(value) return_type_value = re.sub(r"\"([^\"]+)Impl\"", r"\1", return_type_value) event_name = re.sub(r"expect_(.*)", r"\1", name) event_name = re.sub(r"_", "", event_name) event_name = re.sub(r"consolemessage", "console", event_name) print( f""" def {to_snake_case(name)}({signature(value, len(name) + 9)}) -> Async{return_type_value}: \"\"\"{class_name}.{name} Returns context manager that waits for ``event`` to fire upon exit. It passes event's value into the ``predicate`` function and waits for the predicate to return a truthy value. Will throw an error if the page is closed before the ``event`` is fired. async with page.expect_{event_name}() as event_info: await page.click("button") value = event_info.value Parameters ---------- predicate : Optional[typing.Callable[[Any], bool]] Predicate receiving event data. timeout : Optional[int] Maximum wait time in milliseconds, defaults to 30 seconds, pass `0` to disable the timeout. The default value can be changed by using the browserContext.setDefaultTimeout(timeout) or page.setDefaultTimeout(timeout) methods. \"\"\"""") wait_for_method = "waitForEvent(event, predicate, timeout)" if event_name == "request": wait_for_method = "waitForRequest(url_or_predicate, timeout)" elif event_name == "response": wait_for_method = "waitForResponse(url_or_predicate, timeout)" elif event_name == "loadstate": wait_for_method = "waitForLoadState(state, timeout)" elif event_name == "navigation": wait_for_method = "waitForNavigation(url, wait_until, timeout)" elif event_name != "event": print(f' event = "{event_name}"') print( f" return AsyncEventContextManager(self._impl_obj.{wait_for_method})" ) print("") print(f"mapping.register({class_name}Impl, {class_name})")
def register_handler( self, call: Callable[[Any, Message], Optional[Response]]) -> None: """Register a handler call. The message type handled by the call is determined by its type annotation. """ # TODO: can use types.GenericAlias in 3.9. from typing import _GenericAlias # type: ignore from typing import Union, get_type_hints, get_args sig = inspect.getfullargspec(call) # The provided callable should be a method taking one 'msg' arg. expectedsig = ['self', 'msg'] if sig.args != expectedsig: raise ValueError(f'Expected callable signature of {expectedsig};' f' got {sig.args}') # Check annotation types to determine what message types we handle. # Return-type annotation can be a Union, but we probably don't # have it available at runtime. Explicitly pull it in. anns = get_type_hints(call, localns={'Union': Union}) msgtype = anns.get('msg') if not isinstance(msgtype, type): raise TypeError( f'expected a type for "msg" annotation; got {type(msgtype)}.') assert issubclass(msgtype, Message) ret = anns.get('return') responsetypes: Tuple[Union[Type[Any], Type[None]], ...] # Return types can be a single type or a union of types. if isinstance(ret, _GenericAlias): targs = get_args(ret) if not all(isinstance(a, type) for a in targs): raise TypeError(f'expected only types for "return" annotation;' f' got {targs}.') responsetypes = targs else: if not isinstance(ret, type): raise TypeError(f'expected one or more types for' f' "return" annotation; got a {type(ret)}.') responsetypes = (ret, ) # Return type of None translates to EmptyResponse. responsetypes = tuple(EmptyResponse if r is type(None) else r for r in responsetypes) # Make sure our protocol has this message type registered and our # return types exactly match. (Technically we could return a subset # of the supported types; can allow this in the future if it makes # sense). registered_types = self._protocol.message_ids_by_type.keys() if msgtype not in registered_types: raise TypeError(f'Message type {msgtype} is not registered' f' in this Protocol.') if msgtype in self._handlers: raise TypeError(f'Message type {msgtype} already has a registered' f' handler.') # Make sure the responses exactly matches what the message expects. if set(responsetypes) != set(msgtype.get_response_types()): raise TypeError( f'Provided response types {responsetypes} do not' f' match the set expected by message type {msgtype}: ' f'({msgtype.get_response_types()})') # Ok; we're good! self._handlers[msgtype] = call
def test_typing_present(self): assert is_palindromic.__hints__ == typing.get_type_hints(self.is_palindromic_oracle)
def test_typing_present(self): assert leap.__hints__ == typing.get_type_hints(self.leap_oracle)
def __validate_types__( # pylint: disable=too-many-branches; # noqa: C901 cls: Type["BasePropTypes"], ) -> None: """Validate the types of the props defined in the current PropTypes class. Raises ------ PropTypeChoicesError - If a prop is a ``Choices`` with no value or empty list. - If a prop is a ``Choices`` with something else than a list. PropTypeRequiredError - If a prop is a ``DefaultChoices`` and is marked as ``Required``. - For all other props marked as ``Required`` if there is a value. InvalidPropValueError - If the default value is not valid for the prop type. """ cls.__types__ = { name: prop_type for name, prop_type in get_type_hints(cls).items() if not hasattr(BasePropTypes, name) and name not in cls.__excluded_props__ } for name, prop_type in cls.__types__.items(): is_required = False try: if issubclass(prop_type, Required): is_required = True except TypeError: try: if prop_type.__origin__ is Required: is_required = True except AttributeError: pass if is_required: prop_type = prop_type.__args__[0] cls.__types__[name] = prop_type cls.__required_props__.add(name) if cls.__is_choice__(name): if not getattr(cls, name, []): raise PropTypeChoicesError( cls.__owner_name__, name, "a 'choices' prop must have a list of values", ) choices = getattr(cls, name) if not isinstance(choices, Sequence) or isinstance( choices, str): raise PropTypeChoicesError( cls.__owner_name__, name, "the value for a 'choices' prop must be a list", ) if issubclass(cls.__type__(name), DefaultChoices): if choices[0] is not NotProvided: if is_required: raise PropTypeRequiredError( cls.__owner_name__, name, "a 'choices' prop with a default value cannot be required", ) cls.__default_props__[name] = choices[0] continue default = getattr(cls, name, NotProvided) if default is NotProvided: continue if is_required: raise PropTypeRequiredError( cls.__owner_name__, name, "a prop with a default value cannot be required", ) cls.__default_props__[name] = cls.__validate__(name, default)