From 1e5dd7e02a009c45b36c4315695a2e20513837c7 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Mon, 19 Nov 2018 09:47:03 +0100 Subject: [PATCH] Extra cythonize: _repr_iterable_items BoundParameter: subclass inspect.Parameter Signed-off-by: Alexey Stepanov --- doc/source/logwrap.rst | 65 ++++-------------------------------------- logwrap/log_wrap.py | 50 ++++++-------------------------- logwrap/log_wrap.pyx | 57 ++++++++++-------------------------- logwrap/repr_utils.pxd | 1 + logwrap/repr_utils.pyx | 8 ++++-- 5 files changed, 36 insertions(+), 145 deletions(-) diff --git a/doc/source/logwrap.rst b/doc/source/logwrap.rst index c05594d..3d3346a 100644 --- a/doc/source/logwrap.rst +++ b/doc/source/logwrap.rst @@ -111,9 +111,10 @@ API: Decorators: `LogWrap` class and `logwrap` function. :rtype: typing.Union[typing.Callable, typing.Awaitable] -.. py:class:: BoundParameter(object) +.. py:class:: BoundParameter(inspect.Parameter) Parameter-like object store BOUND with value parameter. + .. versionchanged:: 5.3.1 subclass inspect.Parameter .. versionadded:: 3.3.0 @@ -127,65 +128,11 @@ API: Decorators: `LogWrap` class and `logwrap` function. :type value: typing.Any :raises ValueError: No default value and no value - .. py:attribute:: POSITIONAL_ONLY - - ``enum.IntEnum`` - Parameter.POSITIONAL_ONLY - - .. py:attribute:: POSITIONAL_OR_KEYWORD - - ``enum.IntEnum`` - Parameter.POSITIONAL_OR_KEYWORD - - .. py:attribute:: VAR_POSITIONAL - - ``enum.IntEnum`` - Parameter.VAR_POSITIONAL - - .. py:attribute:: KEYWORD_ONLY - - ``enum.IntEnum`` - Parameter.KEYWORD_ONLY - - .. py:attribute:: VAR_KEYWORD - - ``enum.IntEnum`` - Parameter.VAR_KEYWORD - - .. py:attribute:: empty - - ``typing.Type`` - Parameter.empty - .. py:attribute:: parameter Parameter object. - :rtype: inspect.Parameter - - .. py:attribute:: name - - Parameter name. - - :rtype: typing.Union[None, str] - - .. py:attribute:: default - - Parameter default value. - - :rtype: typing.Any - - .. py:attribute:: annotation - - Parameter annotation. - - :rtype: typing.Union[Parameter.empty, str] - - .. py:attribute:: kind - - Parameter kind. - - :rtype: enum.IntEnum + :rtype: BoundParameter .. py:attribute:: value @@ -193,11 +140,11 @@ API: Decorators: `LogWrap` class and `logwrap` function. :rtype: typing.Any - .. py:method:: __hash__(self) + .. py:method:: __str__(self) - Block hashing. + String representation. - :raises TypeError: Not hashable. + :rtype: ``str`` .. py:function:: bind_args_kwargs(sig, *args, **kwargs) diff --git a/logwrap/log_wrap.py b/logwrap/log_wrap.py index 4b76c87..5125962 100644 --- a/logwrap/log_wrap.py +++ b/logwrap/log_wrap.py @@ -23,6 +23,7 @@ import sys import traceback import typing +import warnings import logwrap as core from . import class_decorator @@ -38,21 +39,14 @@ comment = "\n{spc:<{indent}}# {{kind!s}}:".format(spc="", indent=indent).format -class BoundParameter: +class BoundParameter(inspect.Parameter): """Parameter-like object store BOUND with value parameter. .. versionadded:: 3.3.0 + .. versionchanged:: 5.3.1 subclass inspect.Parameter """ - __slots__ = ("_parameter", "_value") - - POSITIONAL_ONLY = inspect.Parameter.POSITIONAL_ONLY - POSITIONAL_OR_KEYWORD = inspect.Parameter.POSITIONAL_OR_KEYWORD - VAR_POSITIONAL = inspect.Parameter.VAR_POSITIONAL - KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY - VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD - - empty = inspect.Parameter.empty + __slots__ = ("_value",) def __init__(self, parameter: inspect.Parameter, value: typing.Any = inspect.Parameter.empty) -> None: """Parameter-like object store BOUND with value parameter. @@ -63,7 +57,9 @@ def __init__(self, parameter: inspect.Parameter, value: typing.Any = inspect.Par :type value: typing.Any :raises ValueError: No default value and no value """ - self._parameter = parameter + super(BoundParameter, self).__init__( + name=parameter.name, kind=parameter.kind, default=parameter.default, annotation=parameter.annotation + ) if value is self.empty: if parameter.default is self.empty and parameter.kind not in (self.VAR_POSITIONAL, self.VAR_KEYWORD): @@ -75,42 +71,14 @@ def __init__(self, parameter: inspect.Parameter, value: typing.Any = inspect.Par @property def parameter(self) -> inspect.Parameter: """Parameter object.""" - return self._parameter - - @property - def name(self) -> typing.Union[None, str]: - """Parameter name.""" - return self.parameter.name - - @property - def default(self) -> typing.Any: - """Parameter default value.""" - return self.parameter.default - - @property - def annotation(self) -> typing.Union[inspect.Parameter.empty, str]: - """Parameter annotation.""" - return self.parameter.annotation - - @property - def kind(self) -> int: - """Parameter kind.""" - return self.parameter.kind # type: ignore + warnings.warn("BoundParameter is subclass of `inspect.Parameter`", DeprecationWarning) + return self @property def value(self) -> typing.Any: """Parameter value.""" return self._value - # noinspection PyTypeChecker - def __hash__(self) -> int: # pragma: no cover - """Block hashing. - - :raises TypeError: Not hashable. - """ - msg = "unhashable type: '{0}'".format(self.__class__.__name__) - raise TypeError(msg) - def __str__(self) -> str: """Debug purposes.""" # POSITIONAL_ONLY is only in precompiled functions diff --git a/logwrap/log_wrap.pyx b/logwrap/log_wrap.pyx index e19447a..c0cdd59 100644 --- a/logwrap/log_wrap.pyx +++ b/logwrap/log_wrap.pyx @@ -21,6 +21,7 @@ import logging import sys import traceback import typing +import warnings from logwrap cimport repr_utils from logwrap cimport class_decorator @@ -36,18 +37,13 @@ fmt = "\n{spc:<{indent}}{{key!r}}={{val}},{{annotation}}".format(spc="", indent= comment = "\n{spc:<{indent}}# {{kind!s}}:".format(spc="", indent=indent).format -class BoundParameter: - """Parameter-like object store BOUND with value parameter.""" +class BoundParameter(inspect.Parameter): + """Parameter-like object store BOUND with value parameter. - __slots__ = ("_parameter", "_value") - - POSITIONAL_ONLY = inspect.Parameter.POSITIONAL_ONLY - POSITIONAL_OR_KEYWORD = inspect.Parameter.POSITIONAL_OR_KEYWORD - VAR_POSITIONAL = inspect.Parameter.VAR_POSITIONAL - KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY - VAR_KEYWORD = inspect.Parameter.VAR_KEYWORD + .. versionchanged:: 5.3.1 subclass inspect.Parameter + """ - empty = inspect.Parameter.empty + __slots__ = ("_value",) def __init__(self, parameter: inspect.Parameter, value: typing.Any = inspect.Parameter.empty) -> None: """Parameter-like object store BOUND with value parameter. @@ -58,7 +54,12 @@ class BoundParameter: :type value: typing.Any :raises ValueError: No default value and no value """ - self._parameter = parameter + super(BoundParameter, self).__init__( + name=parameter.name, + kind=parameter.kind, + default=parameter.default, + annotation=parameter.annotation + ) if value is self.empty: if parameter.default is self.empty and parameter.kind not in (self.VAR_POSITIONAL, self.VAR_KEYWORD): @@ -70,42 +71,14 @@ class BoundParameter: @property def parameter(self) -> inspect.Parameter: """Parameter object.""" - return self._parameter - - @property - def name(self) -> typing.Union[None, str]: - """Parameter name.""" - return self.parameter.name - - @property - def default(self) -> typing.Any: - """Parameter default value.""" - return self.parameter.default - - @property - def annotation(self) -> typing.Union[inspect.Parameter.empty, str]: - """Parameter annotation.""" - return self.parameter.annotation - - @property - def kind(self) -> int: - """Parameter kind.""" - return self.parameter.kind # type: ignore + warnings.warn("BoundParameter is subclass of `inspect.Parameter`", DeprecationWarning) + return self @property def value(self) -> typing.Any: """Parameter value.""" return self._value - # noinspection PyTypeChecker - def __hash__(self) -> int: - """Block hashing. - - :raises TypeError: Not hashable. - """ - cdef str msg = "unhashable type: '{0}'".format(self.__class__.__name__) - raise TypeError(msg) - def __str__(self) -> str: """Debug purposes.""" cdef str as_str @@ -328,7 +301,7 @@ cdef class LogWrap(class_decorator.BaseDecorator): str annotation last_kind = None - for param in bind_args_kwargs(sig, *args, **kwargs): + for param in bind_args_kwargs(sig, *args, **kwargs): # type: BoundParameter if param.name in self.blacklisted_names: continue diff --git a/logwrap/repr_utils.pxd b/logwrap/repr_utils.pxd index 74c0ea5..411395c 100644 --- a/logwrap/repr_utils.pxd +++ b/logwrap/repr_utils.pxd @@ -57,6 +57,7 @@ cdef: str _repr_callable(self, src: typing.Union[types.FunctionType, types.MethodType], unsigned int indent=?) str _repr_simple(self, src: typing.Any, unsigned int indent=?, bint no_indent_start=?) str _repr_iterable_item(self, bint nl, str obj_type, str prefix, unsigned int indent, str result, str suffix) + str _repr_iterable_items(self, src: typing.Iterable, unsigned int indent=?) cpdef str process_element(self, src: typing.Any, unsigned int indent=?, bint no_indent_start=?) diff --git a/logwrap/repr_utils.pyx b/logwrap/repr_utils.pyx index 57aff63..799cd7c 100644 --- a/logwrap/repr_utils.pyx +++ b/logwrap/repr_utils.pyx @@ -192,7 +192,7 @@ cdef class PrettyFormat: """ raise NotImplementedError() - def _repr_iterable_items(self, src: typing.Iterable, unsigned int indent=0) -> typing.Iterator[str]: + cdef str _repr_iterable_items(self, src: typing.Iterable, unsigned int indent=0): """Repr iterable items (not designed for dicts). :param src: object to process @@ -202,8 +202,10 @@ cdef class PrettyFormat: :return: repr of element in iterable item :rtype: typing.Iterator[str] """ + cdef str result = "" for elem in src: - yield "\n" + self.process_element(src=elem, indent=self.next_indent(indent)) + "," + result += "\n" + self.process_element(src=elem, indent=self.next_indent(indent)) + "," + return result cpdef str process_element(self, src: typing.Any, unsigned int indent=0, bint no_indent_start=False): """Make human readable representation of object. @@ -242,7 +244,7 @@ cdef class PrettyFormat: prefix, suffix = "(", ")" else: prefix, suffix = "{", "}" - result = "".join(self._repr_iterable_items(src=src, indent=indent)) + result = self._repr_iterable_items(src=src, indent=indent) return self._repr_iterable_item( nl=no_indent_start, obj_type=src.__class__.__name__,