From 08b7ce953f77167953aaadc12fd1e7cb4ff9ad4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=9Blanka?= <piotr.maslanka@henrietta.com.pl> Date: Sun, 1 Jan 2023 21:35:15 +0100 Subject: [PATCH] did some work on overloading and typing --- docs/coding/functions.rst | 8 ++++++ satella/__init__.py | 2 +- satella/coding/__init__.py | 6 ++-- satella/coding/overloading.py | 52 +++++++++++++++++++++++++++++++---- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/docs/coding/functions.rst b/docs/coding/functions.rst index a9299340..97d4a0a8 100644 --- a/docs/coding/functions.rst +++ b/docs/coding/functions.rst @@ -69,6 +69,14 @@ Function overloading .. autoclass:: satella.coding.overload :members: +.. autofunction:: satella.coding.is_signature_a_more_generic_than_b + + +.. autofunction:: satella.coding.is_type_a_more_generic_than_b + + +.. autofunction:: satella.coding.extract_type_signature_from + DocsFromParent -------------- diff --git a/satella/__init__.py b/satella/__init__.py index 32815b25..1c24e333 100644 --- a/satella/__init__.py +++ b/satella/__init__.py @@ -1 +1 @@ -__version__ = '2.23.1a1' +__version__ = '2.23.1b1' diff --git a/satella/coding/__init__.py b/satella/coding/__init__.py index 72369906..9752da5b 100644 --- a/satella/coding/__init__.py +++ b/satella/coding/__init__.py @@ -18,7 +18,8 @@ from .misc import update_if_not_none, update_key_if_none, update_attr_if_none, q get_arguments, call_with_arguments, chain_callables, Closeable, contains, \ enum_value, length from .environment import Context -from .overloading import overload, class_or_instancemethod +from .overloading import overload, class_or_instancemethod, is_signature_a_more_generic_than_b, \ + is_type_a_more_generic_than_b, extract_type_signature_from from .recast_exceptions import rethrow_as, silence_excs, catch_exception, log_exceptions, \ raises_exception, reraise_as from .expect_exception import expect_exception @@ -29,7 +30,8 @@ __all__ = [ 'assert_equal', 'InequalityReason', 'Inequal', 'Closeable', 'contains', 'enum_value', 'reraise_as', 'expect_exception', - 'overload', 'class_or_instancemethod', + 'overload', 'class_or_instancemethod', 'extract_type_signature_from', 'is_signature_a_more_generic_than_b', + 'is_type_a_more_generic_than_b', 'update_if_not_none', 'DocsFromParent', 'update_key_if_none', 'queue_iterator', 'update_attr_if_none', 'update_key_if_not_none', 'source_to_function', 'update_key_if_true', diff --git a/satella/coding/overloading.py b/satella/coding/overloading.py index 8270de48..d52567be 100644 --- a/satella/coding/overloading.py +++ b/satella/coding/overloading.py @@ -3,16 +3,27 @@ import typing as tp from inspect import Parameter -def extract_type_signature_from(fun: tp.Callable) -> tp.Tuple[type, ...]: - sign = [] +def extract_type_signature_from(fun: tp.Callable) -> tp.Dict[str, type]: + """ + Extract type signature of a function + :param fun: function to extract signature from + :return: a dict, having all parameters normally passed to the function + """ + sign = {} params = inspect.signature(fun).parameters for parameter in params.values(): if parameter.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD): if parameter.annotation == Parameter.empty: - sign.append(None) + sign[parameter.name] = None + else: + sign[parameter.name] = parameter.annotation + elif parameter.kind in (Parameter.KEYWORD_ONLY, Parameter.VAR_KEYWORD): + if parameter.annotation == Parameter.empty: + annot = None else: - sign.append(parameter.annotation) - return tuple(sign) + annot = parameter.annotation + sign[parameter.name] = (parameter.kind == Parameter.KEYWORD_ONLY), annot + return sign # Taken from https://stackoverflow.com/questions/28237955/same-name-for-classmethod-and- @@ -38,6 +49,37 @@ class class_or_instancemethod(classmethod): return descr_get(instance, type_) +def is_type_a_more_generic_than_b(a: tp.Dict[str, tp.Type], b: tp.Dict[str, tp.Type]) -> bool: + """ + Can it be said that type a is more generic than b + :param a: type extracted from a with :func:`~satella.coding.overloading. + :param b: + :return: + """ + if a is None: + return True + for key in a: + key = b.get(key, None) + + a_ = a[key] + b_ = b[key] + if isinstance(a_, tuple): + if not isinstance(b_, tuple): + raise TypeError('Type mismatch %s to %s' % (a_, b_)) + if issubclass(b_, a_): + return True + return False + + +def is_signature_a_more_generic_than_b(a: tp.Tuple[{}, [], []], b) -> bool: + """ + + :param a: + @param b: + :return: is A more generic than B + """ + + class overload: """ A class used for method overloading. -- GitLab