diff --git a/.editorconfig b/.editorconfig index afdae29..c13093d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ insert_final_newline = true trim_trailing_whitespace = true [*.{py,ini}] -max_line_length = 79 +max_line_length = 120 [*.{yml,rst}] indent_size = 2 diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml deleted file mode 100644 index c35acad..0000000 --- a/.idea/codeStyleSettings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - diff --git a/.idea/dictionaries/penguinolog.xml b/.idea/dictionaries/penguinolog.xml deleted file mode 100644 index 25c262a..0000000 --- a/.idea/dictionaries/penguinolog.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - asyncio - awaitable - classmethod - coroutine - genindex - logwrap - modindex - quickstart - toctree - typecheck - ungrouped - - - \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index 8bf1f73..9e6d02f 100644 --- a/.pylintrc +++ b/.pylintrc @@ -273,7 +273,7 @@ logging-modules=logging [FORMAT] # Maximum number of characters on a single line. -max-line-length=80 +max-line-length=120 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 93f3aea..eaa652d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,5 +1,10 @@ CHANGELOG ========= +Version 3.3.0 +------------- +* Type hints and stubs +* PEP0518 + Version 3.2.0 ------------- * Return logwrap function back with 2 branches: with arguments and not due to diff --git a/logwrap/__init__.py b/logwrap/__init__.py index 3c3b726..893c397 100644 --- a/logwrap/__init__.py +++ b/logwrap/__init__.py @@ -34,7 +34,7 @@ pretty_str ) -PY3 = sys.version_info[:2] > (3, 0) +PY3 = sys.version_info[:2] > (3, 0) # type: bool # pylint: disable=no-name-in-module if PY3: # pragma: no cover diff --git a/logwrap/_class_decorator.py b/logwrap/_class_decorator.py index c0cfc64..6dadbe8 100644 --- a/logwrap/_class_decorator.py +++ b/logwrap/_class_decorator.py @@ -1,4 +1,6 @@ -# Copyright 2017 Alexey Stepanov aka penguinolog +#!/usr/bin/env python + +# Copyright 2017-2018 Alexey Stepanov aka penguinolog ## # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -15,19 +17,55 @@ """Base class for decorators.""" from __future__ import absolute_import +from __future__ import print_function import abc import functools import sys import typing # noqa # pylint: disable=unused-import -PY3 = sys.version_info[:2] > (3, 0) +PY3 = sys.version_info[:2] > (3, 0) # type: bool class BaseDecorator(object): """Base class for decorators. Implements wrapping and __call__, wrapper getter is abstract. + + Note: + wrapper getter is called only on function call, + if decorator used without braces. + + Usage example: + + >>> class TestDecorator(BaseDecorator): + ... def _get_function_wrapper(self, func): + ... print('Wrapping: {}'.format(func.__name__)) + ... @functools.wraps(func) + ... def wrapper(*args, **kwargs): + ... print('call_function: {}'.format(func.__name__)) + ... return func(*args, **kwargs) + ... return wrapper + + >>> @TestDecorator + ... def func_no_init(): + ... pass + >>> func_no_init() + Wrapping: func_no_init + call_function: func_no_init + >>> isinstance(func_no_init, TestDecorator) + True + >>> func_no_init._func is func_no_init.__wrapped__ + True + + >>> @TestDecorator() + ... def func_init(): + ... pass + Wrapping: func_init + >>> func_init() + call_function: func_init + >>> isinstance(func_init, TestDecorator) + False """ def __init__( @@ -40,11 +78,11 @@ def __init__( :type func: typing.Optional[typing.Callable] """ # pylint: disable=assigning-non-slot - self.__func = func + self.__func = func # type: typing.Optional[typing.Callable] if self.__func is not None: functools.update_wrapper(self, self.__func) if not PY3: # pragma: no cover - self.__wrapped__ = self.__func + self.__wrapped__ = self.__func # type: typing.Callable # pylint: enable=assigning-non-slot # noinspection PyArgumentList super(BaseDecorator, self).__init__() @@ -52,7 +90,7 @@ def __init__( @property def _func( self - ): # type: (BaseDecorator) -> typing.Optional[typing.Callable] + ): # type: () -> typing.Optional[typing.Callable] """Get wrapped function. :rtype: typing.Optional[typing.Callable] @@ -72,7 +110,11 @@ def _get_function_wrapper( """ raise NotImplementedError() # pragma: no cover - def __call__(self, *args, **kwargs): + def __call__( + self, + *args, # type: typing.Any + **kwargs # type: typing.Any + ): # type: (...) -> typing.Any """Main decorator getter.""" args = list(args) wrapped = self.__func or args.pop(0) @@ -88,3 +130,10 @@ def __repr__(self): func=self.__func, id=id(self) ) # pragma: no cover + + +# 8<---------------------------------------------------------------------------- + +if __name__ == '__main__': + import doctest # pragma: no cover + doctest.testmod(verbose=True) # pragma: no cover diff --git a/logwrap/_class_decorator.pyi b/logwrap/_class_decorator.pyi new file mode 100644 index 0000000..e5163f5 --- /dev/null +++ b/logwrap/_class_decorator.pyi @@ -0,0 +1,8 @@ +import typing + +PY3: bool + +class BaseDecorator: + __wrapped__: typing.Optional[typing.Callable] = ... + def __init__(self, func: typing.Optional[typing.Callable]=...) -> None: ... + def __call__(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Any: ... diff --git a/logwrap/_log_wrap2.py b/logwrap/_log_wrap2.py index 995753a..7387251 100644 --- a/logwrap/_log_wrap2.py +++ b/logwrap/_log_wrap2.py @@ -35,10 +35,6 @@ __all__ = ('logwrap', 'LogWrap') -DEFAULT_DECORATOR_ARGUMENT = typing.Union[logging.Logger, typing.Callable] -BLACKLISTED_EXCEPTIONS_ARGUMENT = typing.Optional[typing.List[Exception]] - - class LogWrap(_log_wrap_shared.BaseLogWrap): """LogWrap.""" @@ -84,13 +80,13 @@ def wrapper(*args, **kwargs): # pylint: disable=unexpected-keyword-arg, no-value-for-parameter def logwrap( - log=_log_wrap_shared.logger, # type: DEFAULT_DECORATOR_ARGUMENT + log=_log_wrap_shared.logger, # type: typing.Union[logging.Logger, typing.Callable] log_level=logging.DEBUG, # type: int exc_level=logging.ERROR, # type: int max_indent=20, # type: int spec=None, # type: typing.Optional[typing.Callable] blacklisted_names=None, # type: typing.Optional[typing.List[str]] - blacklisted_exceptions=None, # type: BLACKLISTED_EXCEPTIONS_ARGUMENT + blacklisted_exceptions=None, # type: typing.Optional[typing.List[Exception]] log_call_args=True, # type: bool log_call_args_on_exc=True, # type: bool log_result_obj=True, # type: bool @@ -112,9 +108,8 @@ def logwrap( Note: this object should provide fully compatible signature with decorated function, or arguments bind will be failed! :type spec: typing.Optional[typing.Callable] - :param blacklisted_names: list of exception, - which should be re-raised without - producing log record. + :param blacklisted_names: Blacklisted argument names. + Arguments with this names will be skipped in log. :type blacklisted_names: typing.Optional[typing.List[str]] :param blacklisted_exceptions: list of exception, which should be re-raised without @@ -130,9 +125,9 @@ def logwrap( :rtype: _log_wrap_shared.BaseLogWrap """ if isinstance(log, logging.Logger): - log, func = log, None + func = None else: - log, func = _log_wrap_shared.logger, log + log, func = _log_wrap_shared.logger, log # type: logging.Logger, typing.Callable wrapper = LogWrap( log=log, diff --git a/logwrap/_log_wrap2.pyi b/logwrap/_log_wrap2.pyi new file mode 100644 index 0000000..9ac631f --- /dev/null +++ b/logwrap/_log_wrap2.pyi @@ -0,0 +1,18 @@ +import logging +import typing +from . import _log_wrap_shared + +class LogWrap(_log_wrap_shared.BaseLogWrap): ... + +def logwrap( + log: typing.Union[logging.Logger, typing.Callable]=..., + log_level: int=..., + exc_level: int=..., + max_indent: int=..., + spec: typing.Optional[typing.Callable]=..., + blacklisted_names: typing.Optional[typing.List[str]]=..., + blacklisted_exceptions: typing.Optional[typing.List[Exception]]=..., + log_call_args: bool=..., + log_call_args_on_exc: bool=..., + log_result_obj: bool=... +) -> typing.Union[LogWrap, typing.Callable]: ... diff --git a/logwrap/_log_wrap3.py b/logwrap/_log_wrap3.py index 7833e75..17eebd7 100644 --- a/logwrap/_log_wrap3.py +++ b/logwrap/_log_wrap3.py @@ -36,9 +36,6 @@ __all__ = ('logwrap', 'LogWrap') -DEFAULT_DECORATOR_ARGUMENT = typing.Union[logging.Logger, typing.Callable] - - class LogWrap(_log_wrap_shared.BaseLogWrap): """Python 3.3+ version of LogWrap.""" @@ -55,7 +52,7 @@ def _get_function_wrapper( :return: wrapped coroutine or function :rtype: typing.Callable """ - sig = inspect.signature(obj=self._spec or func) + sig = inspect.signature(self._spec or func) # pylint: disable=missing-docstring # noinspection PyCompatibility,PyMissingOrEmptyDocstring @@ -112,7 +109,7 @@ def wrapper(*args, **kwargs): # pylint: disable=unexpected-keyword-arg, no-value-for-parameter def logwrap( - log: DEFAULT_DECORATOR_ARGUMENT = _log_wrap_shared.logger, + log: typing.Union[logging.Logger, typing.Callable] = _log_wrap_shared.logger, log_level: int = logging.DEBUG, exc_level: int = logging.ERROR, max_indent: int = 20, @@ -140,9 +137,8 @@ def logwrap( Note: this object should provide fully compatible signature with decorated function, or arguments bind will be failed! :type spec: typing.Optional[typing.Callable] - :param blacklisted_names: list of exception, - which should be re-raised without - producing log record. + :param blacklisted_names: Blacklisted argument names. + Arguments with this names will be skipped in log. :type blacklisted_names: typing.Optional[typing.Iterable[str]] :param blacklisted_exceptions: list of exception, which should be re-raised without @@ -158,9 +154,9 @@ def logwrap( :rtype: _log_wrap_shared.BaseLogWrap """ if isinstance(log, logging.Logger): - log, func = log, None + func = None else: - log, func = _log_wrap_shared.logger, log + log, func = _log_wrap_shared.logger, log # type: logging.Logger, typing.Callable wrapper = LogWrap( log=log, diff --git a/logwrap/_log_wrap3.pyi b/logwrap/_log_wrap3.pyi new file mode 100644 index 0000000..9ac631f --- /dev/null +++ b/logwrap/_log_wrap3.pyi @@ -0,0 +1,18 @@ +import logging +import typing +from . import _log_wrap_shared + +class LogWrap(_log_wrap_shared.BaseLogWrap): ... + +def logwrap( + log: typing.Union[logging.Logger, typing.Callable]=..., + log_level: int=..., + exc_level: int=..., + max_indent: int=..., + spec: typing.Optional[typing.Callable]=..., + blacklisted_names: typing.Optional[typing.List[str]]=..., + blacklisted_exceptions: typing.Optional[typing.List[Exception]]=..., + log_call_args: bool=..., + log_call_args_on_exc: bool=..., + log_result_obj: bool=... +) -> typing.Union[LogWrap, typing.Callable]: ... diff --git a/logwrap/_log_wrap_shared.py b/logwrap/_log_wrap_shared.py index e3a95d3..6e834ec 100644 --- a/logwrap/_log_wrap_shared.py +++ b/logwrap/_log_wrap_shared.py @@ -22,14 +22,14 @@ import functools import inspect # noqa # pylint: disable=unused-import import logging -import typing +import typing # noqa # pylint: disable=unused-import import logwrap as core from . import _class_decorator __all__ = ('BaseLogWrap', ) -logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) # type: logging.Logger indent = 4 @@ -40,18 +40,12 @@ comment = "\n{spc:<{indent}}# {{kind!s}}:".format(spc='', indent=indent).format -# Long arguments types: -_LoggerArg = typing.Union[logging.Logger, typing.Callable] -_BlacklistedNamesArg = typing.Optional[typing.Iterable[str]] -_BlacklistedExceptionsArg = typing.Optional[typing.Iterable[Exception]] - - -def _check_type(expected): +def _check_type(expected): # type: (type) -> typing.Callable """Check type before assign. :type expected: type """ - def deco(func): + def deco(func): # type: (typing.Callable) -> typing.Callable """Check type before assign.""" # pylint: disable=missing-docstring # noinspection PyMissingOrEmptyDocstring @@ -92,13 +86,13 @@ class BaseLogWrap(_class_decorator.BaseDecorator): def __init__( self, - log=logger, # type: _LoggerArg + log=logger, # type: typing.Union[logging.Logger, typing.Callable] log_level=logging.DEBUG, # type: int exc_level=logging.ERROR, # type: int max_indent=20, # type: int spec=None, # type: typing.Optional[typing.Callable] - blacklisted_names=None, # type: _BlacklistedNamesArg - blacklisted_exceptions=None, # type: _BlacklistedExceptionsArg + blacklisted_names=None, # type: typing.Optional[typing.Iterable[str]] + blacklisted_exceptions=None, # type: typing.Optional[typing.Iterable[Exception]] log_call_args=True, # type: bool log_call_args_on_exc=True, # type: bool log_result_obj=True, # type: bool @@ -141,18 +135,18 @@ def __init__( """ # Typing fix: if blacklisted_names is None: - self.__blacklisted_names = [] + self.__blacklisted_names = [] # type: typing.List[str] else: self.__blacklisted_names = list(blacklisted_names) if blacklisted_exceptions is None: - self.__blacklisted_exceptions = [] + self.__blacklisted_exceptions = [] # type: typing.List[Exception] else: self.__blacklisted_exceptions = list(blacklisted_exceptions) if not isinstance(log, logging.Logger): - func, self.__logger = log, logger + func, self.__logger = log, logger # type: typing.Callable, logging.Logger else: - func, self.__logger = None, log + func, self.__logger = None, log # type: None, logging.Logger super(BaseLogWrap, self).__init__(func=func) self.__log_level = log_level diff --git a/logwrap/_log_wrap_shared.pyi b/logwrap/_log_wrap_shared.pyi new file mode 100644 index 0000000..e9caca2 --- /dev/null +++ b/logwrap/_log_wrap_shared.pyi @@ -0,0 +1,62 @@ +import logging +import typing +from . import _class_decorator + +logger: logging.Logger + +class BaseLogWrap(_class_decorator.BaseDecorator): + def __init__( + self, + log: typing.Union[logging.Logger, typing.Callable]=..., + log_level: int=..., + exc_level: int=..., + max_indent: int=..., + spec: typing.Optional[typing.Callable]=..., + blacklisted_names: typing.Optional[typing.Iterable[str]]=..., + blacklisted_exceptions: typing.Optional[typing.Iterable[Exception]]=..., + log_call_args: bool=..., + log_call_args_on_exc: bool=..., + log_result_obj: bool=... + ) -> None: ... + + @property + def log_level(self) -> int: ... + + @log_level.setter + def log_level(self, val: int) -> None: ... + + @property + def exc_level(self) -> int: ... + + @exc_level.setter + def exc_level(self, val: int) -> None: ... + + @property + def max_indent(self) -> int: ... + + @max_indent.setter + def max_indent(self, val: int) -> None: ... + + @property + def blacklisted_names(self) -> typing.List[str]: ... + + @property + def blacklisted_exceptions(self) -> typing.List[Exception]: ... + + @property + def log_call_args(self) -> bool: ... + + @log_call_args.setter + def log_call_args(self, val: bool) -> None: ... + + @property + def log_call_args_on_exc(self) -> bool: ... + + @log_call_args_on_exc.setter + def log_call_args_on_exc(self, val: bool) -> None: ... + + @property + def log_result_obj(self) -> bool: ... + + @log_result_obj.setter + def log_result_obj(self, val: bool) -> None: ... diff --git a/logwrap/_repr_utils.py b/logwrap/_repr_utils.py index 99ee6e8..17c8207 100644 --- a/logwrap/_repr_utils.py +++ b/logwrap/_repr_utils.py @@ -43,25 +43,27 @@ # pylint: enable=ungrouped-imports, no-name-in-module -def _known_callable(item): +def _known_callable(item): # type: (typing.Any) -> bool """Check for possibility to parse callable.""" return isinstance(item, (types.FunctionType, types.MethodType)) -def _simple(item): +def _simple(item): # type: (typing.Any) -> bool """Check for nested iterations: True, if not.""" return not isinstance(item, (list, set, tuple, dict, frozenset)) # pylint: disable=no-member -def _prepare_repr(func): +def _prepare_repr( + func # type: typing.Union[types.FunctionType, types.MethodType] +): # type: (...) -> typing.Iterator[typing.Union[str, typing.Tuple[str, typing.Any]]] """Get arguments lists with defaults. :type func: typing.Union[types.FunctionType, types.MethodType] - :rtype: typing.Generator[str] + :rtype: typing.Iterator[typing.Union[str, typing.Tuple[str, typing.Any]]] """ isfunction = isinstance(func, types.FunctionType) - real_func = func if isfunction else func.__func__ + real_func = func if isfunction else func.__func__ # type: typing.Callable parameters = list(signature(real_func).parameters.values()) @@ -141,7 +143,11 @@ def next_indent(self, indent, multiplier=1): # type: (int, int) -> int """ return indent + multiplier * self.indent_step - def _repr_callable(self, src, indent=0): + def _repr_callable( + self, + src, # type: typing.Union[types.FunctionType, types.MethodType] + indent=0 # type: int + ): # type: (...) -> six.text_type """Repr callable object (function or method). :type src: typing.Union[types.FunctionType, types.MethodType] @@ -150,7 +156,12 @@ def _repr_callable(self, src, indent=0): """ raise NotImplementedError # pragma: no cover - def _repr_simple(self, src, indent=0, no_indent_start=False): + def _repr_simple( + self, + src, # type: typing.Any + indent=0, # type: int + no_indent_start=False # type: bool + ): # type: (...) -> six.text_type """Repr object without iteration. :type src: typing.Union[ @@ -163,26 +174,30 @@ def _repr_simple(self, src, indent=0, no_indent_start=False): """ raise NotImplementedError() # pragma: no cover - def _repr_dict_items(self, src, indent=0): + def _repr_dict_items( + self, + src, # type: typing.Dict + indent=0 # type: int + ): # type: (...) -> typing.Iterator[str] """Repr dict items. :param src: object to process - :type src: dict + :type src: typing.Dict :param indent: start indentation :type indent: int - :rtype: typing.Generator[str] + :rtype: typing.Iterator[str] """ raise NotImplementedError() # pragma: no cover @staticmethod def _repr_iterable_item( - nl, - obj_type, - prefix, - indent, - result, - suffix, - ): + nl, # type: bool + obj_type, # type: str + prefix, # type: str + indent, # type: int + result, # type: str + suffix, # type: str + ): # type: (...) -> six.text_type """Repr iterable item. :param nl: newline before item @@ -201,14 +216,18 @@ def _repr_iterable_item( """ raise NotImplementedError() # pragma: no cover - def _repr_iterable_items(self, src, indent=0): + def _repr_iterable_items( + self, + src, # type: typing.Iterable + indent=0 # type: int + ): # type: (...) -> typing.Iterator[str] """Repr iterable items (not designed for dicts). :param src: object to process :type src: typing.Iterable :param indent: start indentation :type indent: int - :rtype: typing.Generator[str] + :rtype: typing.Iterator[str] """ for elem in src: yield '\n' + self.process_element( @@ -217,7 +236,7 @@ def _repr_iterable_items(self, src, indent=0): ) + ',' @property - def _magic_method_name(self): + def _magic_method_name(self): # type: () -> six.text_type """Magic method name. :rtype: str @@ -331,7 +350,7 @@ class PrettyRepr(PrettyFormat): __slots__ = () @property - def _magic_method_name(self): + def _magic_method_name(self): # type: () -> six.text_type """Magic method name. :rtype: str @@ -339,7 +358,10 @@ def _magic_method_name(self): return '__pretty_repr__' @staticmethod - def _strings_repr(indent, val): + def _strings_repr( + indent, # type: int + val # type: typing.Union[six.binary_type, six.text_type] + ): # type: (...) -> six.text_type """Custom repr for strings and binary strings.""" if isinstance(val, six.binary_type): val = val.decode( @@ -356,7 +378,12 @@ def _strings_repr(indent, val): string=val ) - def _repr_simple(self, src, indent=0, no_indent_start=False): + def _repr_simple( + self, + src, # type: typing.Any + indent=0, # type: int + no_indent_start=False # type: bool + ): # type: (...) -> six.text_type """Repr object without iteration. :type src: typing.Union[ @@ -382,14 +409,18 @@ def _repr_simple(self, src, indent=0, no_indent_start=False): val=src, ) - def _repr_dict_items(self, src, indent=0): + def _repr_dict_items( + self, + src, # type: typing.Dict + indent=0 # type: int + ): # type: (...) -> typing.Iterator[str] """Repr dict items. :param src: object to process :type src: dict :param indent: start indentation :type indent: int - :rtype: typing.Generator[str] + :rtype: typing.Iterator[str] """ max_len = max((len(repr(key)) for key in src)) if src else 0 for key, val in src.items(): @@ -405,7 +436,11 @@ def _repr_dict_items(self, src, indent=0): ) ) - def _repr_callable(self, src, indent=0): + def _repr_callable( + self, + src, # type: typing.Union[types.FunctionType, types.MethodType] + indent=0 # type: int + ): # type: (...) -> six.text_type """Repr callable object (function or method). :type src: typing.Union[types.FunctionType, types.MethodType] @@ -444,13 +479,13 @@ def _repr_callable(self, src, indent=0): @staticmethod def _repr_iterable_item( - nl, - obj_type, - prefix, - indent, - result, - suffix, - ): + nl, # type: bool + obj_type, # type: str + prefix, # type: str + indent, # type: int + result, # type: str + suffix, # type: str + ): # type: (...) -> six.text_type """Repr iterable item. :param nl: newline before item @@ -491,7 +526,7 @@ class PrettyStr(PrettyFormat): __slots__ = () @property - def _magic_method_name(self): + def _magic_method_name(self): # type: () -> six.text_type """Magic method name. :rtype: str @@ -499,7 +534,10 @@ def _magic_method_name(self): return '__pretty_str__' @staticmethod - def _strings_str(indent, val): + def _strings_str( + indent, # type: int + val # type: typing.Union[six.binary_type, six.text_type] + ): # type: (...) -> six.text_type """Custom repr for strings and binary strings.""" if isinstance(val, six.binary_type): val = val.decode( @@ -512,7 +550,12 @@ def _strings_str(indent, val): string=val ) - def _repr_simple(self, src, indent=0, no_indent_start=False): + def _repr_simple( + self, + src, # type: typing.Any + indent=0, # type: int + no_indent_start=False # type: bool + ): # type: (...) -> six.text_type """Repr object without iteration. :type src: typing.Union[ @@ -538,7 +581,11 @@ def _repr_simple(self, src, indent=0, no_indent_start=False): val=src, ) - def _repr_dict_items(self, src, indent=0): + def _repr_dict_items( + self, + src, # type: typing.Dict + indent=0 # type: int + ): # type: (...) -> typing.Iterator[str] """Repr dict items. :param src: object to process @@ -561,7 +608,11 @@ def _repr_dict_items(self, src, indent=0): ) ) - def _repr_callable(self, src, indent=0): + def _repr_callable( + self, + src, # type: typing.Union[types.FunctionType, types.MethodType] + indent=0 # type: int + ): # type: (...) -> six.text_type """Repr callable object (function or method). :type src: typing.Union[types.FunctionType, types.MethodType] @@ -600,13 +651,13 @@ def _repr_callable(self, src, indent=0): @staticmethod def _repr_iterable_item( - nl, - obj_type, - prefix, - indent, - result, - suffix, - ): + nl, # type: bool + obj_type, # type: str + prefix, # type: str + indent, # type: int + result, # type: str + suffix, # type: str + ): # type: (...) -> six.text_type """Repr iterable item. :param nl: newline before item diff --git a/logwrap/_repr_utils.pyi b/logwrap/_repr_utils.pyi new file mode 100644 index 0000000..5c5fc79 --- /dev/null +++ b/logwrap/_repr_utils.pyi @@ -0,0 +1,44 @@ +import typing + +import six + +class PrettyFormat: + def __init__( + self, + max_indent: int=..., + indent_step: int=..., + py2_str: bool=... + ) -> None: ... + + @property + def max_indent(self) -> int: ... + + @property + def indent_step(self) -> int: ... + + def next_indent(self, indent: int, multiplier: int=...) -> int: ... + + def process_element(self, src: typing.Any, indent: int=..., no_indent_start: bool=...) -> six.text_type: ... + + def __call__(self, src: typing.Any, indent: int=..., no_indent_start: bool=...) -> typing.Union[six.text_type, str]: ... + +class PrettyRepr(PrettyFormat): ... +class PrettyStr(PrettyFormat): ... + +def pretty_repr( + src: typing.Any, + indent: int=..., + no_indent_start: bool=..., + max_indent: int=..., + indent_step: int=..., + py2_str: bool=... +) -> typing.Union[six.text_type, str]: ... + +def pretty_str( + src: typing.Any, + indent: int=..., + no_indent_start: bool=..., + max_indent: int=..., + indent_step: int=..., + py2_str: bool=... +) -> typing.Union[six.text_type, str]: ... diff --git a/setup.py b/setup.py index 80ac0d8..9f1d299 100644 --- a/setup.py +++ b/setup.py @@ -22,6 +22,7 @@ import collections from distutils.command import build_ext import distutils.errors +import glob import os.path import shutil import sys @@ -260,6 +261,12 @@ def get_simple_vars_from_src(src): ], }, install_requires=required, + package_data={ + 'logwrap': [ + os.path.basename(filename) + for filename in glob.glob(os.path.join('logwrap', '*.pyi')) + ], + }, ) if PY3 and cythonize is not None: setup_args['ext_modules'] = ext_modules diff --git a/tox.ini b/tox.ini index 3ab8f28..86f807b 100644 --- a/tox.ini +++ b/tox.ini @@ -101,6 +101,7 @@ ignore = show-pep8 = True show-source = True count = True +max-line-length = 120 [testenv:docs] deps =