From c28ef4ed30e2806b033678d726e4e5989fdb5aa8 Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Fri, 21 Sep 2018 14:35:06 +0200 Subject: [PATCH 1/2] Use black codestyle Signed-off-by: Alexey Stepanov --- README.rst | 2 + pyproject.toml | 5 ++ setup.cfg | 12 ++- setup.py | 94 ++++++------------- test/async_syntax/test_pooled_async.py | 9 +- test/test_gevent_threadpooled.py | 5 +- test/test_pooled.py | 5 +- test/test_pooled_coroutine.py | 9 +- test/test_threaded.py | 1 + threaded/__init__.py | 14 +-- threaded/_asynciotask.py | 66 ++++---------- threaded/_base_threaded.py | 9 +- threaded/_class_decorator.py | 28 ++---- threaded/_gthreadpooled.py | 27 ++---- threaded/_threaded.py | 69 ++++---------- threaded/_threadpooled.py | 119 ++++++------------------- tox.ini | 23 ++++- 17 files changed, 158 insertions(+), 339 deletions(-) diff --git a/README.rst b/README.rst index 4767cfd..08f02f0 100644 --- a/README.rst +++ b/README.rst @@ -16,6 +16,8 @@ threaded :target: https://pypi.python.org/pypi/threaded .. image:: https://img.shields.io/github/license/python-useful-helpers/threaded.svg :target: https://raw.githubusercontent.com/python-useful-helpers/threaded/master/LICENSE +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black threaded is a set of decorators, which wrap functions in: diff --git a/pyproject.toml b/pyproject.toml index 1c48e2c..1cf2044 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,3 +5,8 @@ requires = [ "setuptools >= 21.0.0,!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0", # PSF/ZPL "wheel", ] + +[tool.black] +line-length = 120 +skip-string-normalization = true +safe = true diff --git a/setup.cfg b/setup.cfg index a7c8525..524af15 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,13 +38,23 @@ exclude = __init__.py, docs ignore = + E203 +# whitespace before ':' show-pep8 = True show-source = True count = True max-line-length = 120 [pydocstyle] -ignore = D401, D203, D213 +ignore = + D401, + D202, + D203, + D213 +# First line should be in imperative mood; try rephrasing +# No blank lines allowed after function docstring +# 1 blank line required before class docstring +# Multi-line docstring summary should start at the second line [aliases] test=pytest diff --git a/setup.py b/setup.py index 1611f29..d4131c2 100644 --- a/setup.py +++ b/setup.py @@ -23,25 +23,22 @@ import sys try: + # noinspection PyPackageRequirements from Cython.Build import cythonize + # noinspection PyPackageRequirements import gevent except ImportError: gevent = cythonize = None import setuptools -with open( - os.path.join( - os.path.dirname(__file__), - 'threaded', '__init__.py' - ) -) as f: +with open(os.path.join(os.path.dirname(__file__), 'threaded', '__init__.py')) as f: source = f.read() with open('requirements.txt') as f: required = f.read().splitlines() -with open('README.rst',) as f: +with open('README.rst') as f: long_description = f.read() @@ -60,24 +57,24 @@ def _extension(modpath): ] if 'win32' != sys.platform: - requires_optimization.append( - _extension('threaded.__init__') - ) - -ext_modules = cythonize( - requires_optimization, - compiler_directives=dict( - always_allow_keywords=True, - binding=True, - embedsignature=True, - overflowcheck=True, - language_level=3, + requires_optimization.append(_extension('threaded.__init__')) + +# noinspection PyCallingNonCallable +ext_modules = ( + cythonize( + requires_optimization, + compiler_directives=dict( + always_allow_keywords=True, binding=True, embedsignature=True, overflowcheck=True, language_level=3 + ), ) -) if cythonize is not None else [] + if cythonize is not None + else [] +) class BuildFailed(Exception): """For install clear scripts.""" + pass @@ -103,7 +100,7 @@ def run(self): shutil.copyfile(src, dst) except ( distutils.errors.DistutilsPlatformError, - getattr(globals()['__builtins__'], 'FileNotFoundError', OSError) + getattr(globals()['__builtins__'], 'FileNotFoundError', OSError), ): raise BuildFailed() @@ -115,7 +112,7 @@ def build_extension(self, ext): distutils.errors.CCompilerError, distutils.errors.DistutilsExecError, distutils.errors.DistutilsPlatformError, - ValueError + ValueError, ): raise BuildFailed() @@ -167,11 +164,7 @@ def get_simple_vars_from_src(src): >>> get_simple_vars_from_src(multiple_assign) OrderedDict([('e', 1), ('f', 1), ('g', 1)]) """ - ast_data = ( - ast.Str, ast.Num, - ast.List, ast.Set, ast.Dict, ast.Tuple, - ast.Bytes, ast.NameConstant, - ) + ast_data = (ast.Str, ast.Num, ast.List, ast.Set, ast.Dict, ast.Tuple, ast.Bytes, ast.NameConstant) tree = ast.parse(src) @@ -183,9 +176,7 @@ def get_simple_vars_from_src(src): try: if isinstance(node.value, ast_data): value = ast.literal_eval(node.value) - elif isinstance( # NameConstant in python < 3.4 - node.value, ast.Name - ) and isinstance( + elif isinstance(node.value, ast.Name) and isinstance( # NameConstant in python < 3.4 node.value.ctx, ast.Load # Read constant ): value = ast.literal_eval(node.value) @@ -194,11 +185,7 @@ def get_simple_vars_from_src(src): except ValueError: continue for tgt in node.targets: - if isinstance( - tgt, ast.Name - ) and isinstance( - tgt.ctx, ast.Store - ): + if isinstance(tgt, ast.Name) and isinstance(tgt.ctx, ast.Store): result[tgt.id] = value return result @@ -207,37 +194,25 @@ def get_simple_vars_from_src(src): classifiers = [ 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ] -keywords = [ - 'pooling', - 'multithreading', - 'threading', - 'asyncio', - 'gevent', - 'development', -] +keywords = ['pooling', 'multithreading', 'threading', 'asyncio', 'gevent', 'development'] setup_args = dict( name='threaded', author=variables['__author__'], author_email=variables['__author_email__'], maintainer=', '.join( - '{name} <{email}>'.format(name=name, email=email) - for name, email in variables['__maintainers__'].items() + '{name} <{email}>'.format(name=name, email=email) for name, email in variables['__maintainers__'].items() ), url=variables['__url__'], version=variables['__version__'], @@ -254,17 +229,11 @@ def get_simple_vars_from_src(src): # Blacklist setuptools 34.0.0-34.3.2 due to https://github.com/pypa/setuptools/issues/951 # Blacklist setuptools 36.2.0 due to https://github.com/pypa/setuptools/issues/1086 setup_requires="setuptools >= 21.0.0,!=24.0.0," - "!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2," - "!=36.2.0", - extras_require={ - 'gevent': [ - 'gevent >= 1.2.2' - ], - }, + "!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2," + "!=36.2.0", + extras_require={'gevent': ['gevent >= 1.2.2']}, install_requires=required, - package_data={ - 'threaded': ['py.typed'], - }, + package_data={'threaded': ['py.typed']}, ) if cythonize is not None: setup_args['ext_modules'] = ext_modules @@ -273,12 +242,7 @@ def get_simple_vars_from_src(src): try: setuptools.setup(**setup_args) except BuildFailed: - print( - '*' * 80 + '\n' - '* Build Failed!\n' - '* Use clear scripts version.\n' - '*' * 80 + '\n' - ) + print('*' * 80 + '\n' '* Build Failed!\n' '* Use clear scripts version.\n' '*' * 80 + '\n') del setup_args['ext_modules'] del setup_args['cmdclass'] setuptools.setup(**setup_args) diff --git a/test/async_syntax/test_pooled_async.py b/test/async_syntax/test_pooled_async.py index 3a40e13..91a67cb 100644 --- a/test/async_syntax/test_pooled_async.py +++ b/test/async_syntax/test_pooled_async.py @@ -66,16 +66,11 @@ def test_thread_pooled_loop_getter_context(self): def loop_getter(target): return target - @threaded.threadpooled( - loop_getter=loop_getter, - loop_getter_need_context=True - ) + @threaded.threadpooled(loop_getter=loop_getter, loop_getter_need_context=True) async def test(*args, **kwargs): return threading.current_thread().name - pooled_name = loop.run_until_complete( - asyncio.wait_for(test(loop), 1) - ) + pooled_name = loop.run_until_complete(asyncio.wait_for(test(loop), 1)) self.assertNotEqual(pooled_name, threading.current_thread().name) diff --git a/test/test_gevent_threadpooled.py b/test/test_gevent_threadpooled.py index ef06000..6cd3e8b 100644 --- a/test/test_gevent_threadpooled.py +++ b/test/test_gevent_threadpooled.py @@ -50,10 +50,7 @@ def test_thread_pooled_config(self): thread_pooled = threaded.gthreadpooled() thread_pooled.configure() - self.assertEqual( - thread_pooled.executor.maxsize, - (os.cpu_count() or 1) * 5 - ) + self.assertEqual(thread_pooled.executor.maxsize, (os.cpu_count() or 1) * 5) thread_pooled.configure(max_workers=2) diff --git a/test/test_pooled.py b/test/test_pooled.py index 3062460..cf20f84 100644 --- a/test/test_pooled.py +++ b/test/test_pooled.py @@ -43,10 +43,7 @@ def test(): def test_thread_pooled_config(self): thread_pooled = threaded.threadpooled() - self.assertEqual( - thread_pooled.executor.max_workers, - (cpu_count() or 1) * 5 - ) + self.assertEqual(thread_pooled.executor.max_workers, (cpu_count() or 1) * 5) thread_pooled.configure(max_workers=2) diff --git a/test/test_pooled_coroutine.py b/test/test_pooled_coroutine.py index 43cfe38..4e97b78 100644 --- a/test/test_pooled_coroutine.py +++ b/test/test_pooled_coroutine.py @@ -70,17 +70,12 @@ def test_thread_pooled_loop_getter_context(self): def loop_getter(target): return target - @threaded.threadpooled( - loop_getter=loop_getter, - loop_getter_need_context=True - ) + @threaded.threadpooled(loop_getter=loop_getter, loop_getter_need_context=True) @asyncio.coroutine def test(*args, **kwargs): return threading.current_thread().name - pooled_name = loop.run_until_complete( - asyncio.wait_for(test(loop), 1) - ) + pooled_name = loop.run_until_complete(asyncio.wait_for(test(loop), 1)) self.assertNotEqual(pooled_name, threading.current_thread().name) diff --git a/test/test_threaded.py b/test/test_threaded.py index 24f2474..2fc3ab7 100644 --- a/test/test_threaded.py +++ b/test/test_threaded.py @@ -23,6 +23,7 @@ def test_add_basic(self): @threaded.threaded def func_test(): pass + # pylint: disable=assignment-from-no-return test_thread = func_test() # pylint: enable=assignment-from-no-return diff --git a/threaded/__init__.py b/threaded/__init__.py index 082b9e5..48ca8c1 100644 --- a/threaded/__init__.py +++ b/threaded/__init__.py @@ -30,16 +30,16 @@ __all__ = ( - 'ThreadPooled', 'Threaded', - 'threadpooled', 'threaded', - 'AsyncIOTask', 'asynciotask' + 'ThreadPooled', + 'Threaded', + 'threadpooled', + 'threaded', + 'AsyncIOTask', + 'asynciotask', ) # type: typing.Tuple[str, ...] if GThreadPooled is not None: # pragma: no cover - __all__ += ( - 'GThreadPooled', - 'gthreadpooled' - ) + __all__ += ('GThreadPooled', 'gthreadpooled') __version__ = '2.0.2' __author__ = "Alexey Stepanov" diff --git a/threaded/_asynciotask.py b/threaded/_asynciotask.py index b415731..5776b20 100644 --- a/threaded/_asynciotask.py +++ b/threaded/_asynciotask.py @@ -20,27 +20,20 @@ from . import _class_decorator -__all__ = ( - 'AsyncIOTask', - 'asynciotask', -) +__all__ = ('AsyncIOTask', 'asynciotask') class AsyncIOTask(_class_decorator.BaseDecorator): """Wrap to asyncio.Task.""" - __slots__ = ( - '__loop_getter', - '__loop_getter_need_context', - ) + __slots__ = ('__loop_getter', '__loop_getter_need_context') def __init__( self, func: typing.Optional[typing.Callable[..., 'typing.Awaitable']] = None, *, loop_getter: typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop + typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop ] = asyncio.get_event_loop, loop_getter_need_context: bool = False ) -> None: @@ -61,12 +54,7 @@ def __init__( self.__loop_getter_need_context = loop_getter_need_context @property - def loop_getter( - self - ) -> typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ]: + def loop_getter(self) -> typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop]: """Loop getter. :rtype: typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] @@ -81,11 +69,7 @@ def loop_getter_need_context(self) -> bool: """ return self.__loop_getter_need_context - def get_loop( - self, - *args, # type: typing.Any - **kwargs # type: typing.Any - ) -> asyncio.AbstractEventLoop: + def get_loop(self, *args, **kwargs): # type: (typing.Any, typing.Any) -> asyncio.AbstractEventLoop """Get event loop in decorator class.""" if callable(self.loop_getter): if self.loop_getter_need_context: @@ -94,8 +78,7 @@ def get_loop( return self.loop_getter def _get_function_wrapper( - self, - func: typing.Callable[..., 'typing.Awaitable'] + self, func: typing.Callable[..., 'typing.Awaitable'] ) -> typing.Callable[..., asyncio.Task]: """Here should be constructed and returned real decorator. @@ -106,19 +89,14 @@ def _get_function_wrapper( """ # noinspection PyMissingOrEmptyDocstring @functools.wraps(func) # pylint: disable=missing-docstring - def wrapper( - *args, # type: typing.Any - **kwargs # type: typing.Any - ) -> asyncio.Task: + def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> asyncio.Task loop = self.get_loop(*args, **kwargs) return loop.create_task(func(*args, **kwargs)) return wrapper def __call__( # pylint: disable=useless-super-delegation - self, - *args: typing.Union[typing.Callable[..., 'typing.Awaitable'], typing.Any], - **kwargs: typing.Any + self, *args: typing.Union[typing.Callable[..., 'typing.Awaitable'], typing.Any], **kwargs: typing.Any ) -> typing.Union[asyncio.Task, typing.Callable[..., asyncio.Task]]: """Callable instance.""" return super(AsyncIOTask, self).__call__(*args, **kwargs) # type: ignore @@ -130,12 +108,7 @@ def __repr__(self) -> str: "{func!r}, " "loop_getter={self.loop_getter!r}, " "loop_getter_need_context={self.loop_getter_need_context!r}, " - ") at 0x{id:X}>".format( - cls=self.__class__.__name__, - func=self._func, - self=self, - id=id(self) - ) + ") at 0x{id:X}>".format(cls=self.__class__.__name__, func=self._func, self=self, id=id(self)) ) # pragma: no cover @@ -145,8 +118,7 @@ def asynciotask( func: None = None, *, loop_getter: typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop + typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop ] = asyncio.get_event_loop, loop_getter_need_context: bool = False ) -> AsyncIOTask: @@ -159,8 +131,7 @@ def asynciotask( func: typing.Callable[..., 'typing.Awaitable'], *, loop_getter: typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop + typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop ] = asyncio.get_event_loop, loop_getter_need_context: bool = False ) -> typing.Callable[..., asyncio.Task]: @@ -173,8 +144,7 @@ def asynciotask( # noqa: F811 func: typing.Optional[typing.Callable[..., 'typing.Awaitable']] = None, *, loop_getter: typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop + typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop ] = asyncio.get_event_loop, loop_getter_need_context: bool = False ) -> typing.Union[AsyncIOTask, typing.Callable[..., asyncio.Task]]: @@ -193,14 +163,10 @@ def asynciotask( # noqa: F811 :rtype: typing.Union[AsyncIOTask, typing.Callable[..., asyncio.Task]] """ if func is None: - return AsyncIOTask( - func=func, - loop_getter=loop_getter, - loop_getter_need_context=loop_getter_need_context - ) + return AsyncIOTask(func=func, loop_getter=loop_getter, loop_getter_need_context=loop_getter_need_context) return AsyncIOTask( # type: ignore - func=None, - loop_getter=loop_getter, - loop_getter_need_context=loop_getter_need_context + func=None, loop_getter=loop_getter, loop_getter_need_context=loop_getter_need_context )(func) + + # pylint: enable=function-redefined diff --git a/threaded/_base_threaded.py b/threaded/_base_threaded.py index 28e0e33..5bf5cd6 100644 --- a/threaded/_base_threaded.py +++ b/threaded/_base_threaded.py @@ -20,9 +20,7 @@ from . import _class_decorator -__all__ = ( - 'APIPooled', -) +__all__ = ('APIPooled',) class APIPooled(_class_decorator.BaseDecorator, metaclass=abc.ABCMeta): @@ -34,10 +32,7 @@ class APIPooled(_class_decorator.BaseDecorator, metaclass=abc.ABCMeta): @classmethod @abc.abstractmethod - def configure( - cls: typing.Type['APIPooled'], - max_workers: typing.Optional[int] = None, - ) -> None: + def configure(cls: typing.Type['APIPooled'], max_workers: typing.Optional[int] = None) -> None: """Pool executor create and configure. :param max_workers: Maximum workers diff --git a/threaded/_class_decorator.py b/threaded/_class_decorator.py index 5b3d11b..2135583 100644 --- a/threaded/_class_decorator.py +++ b/threaded/_class_decorator.py @@ -63,10 +63,7 @@ class BaseDecorator(metaclass=abc.ABCMeta): False """ - def __init__( - self, - func: typing.Optional[typing.Callable] = None - ) -> None: + def __init__(self, func: typing.Optional[typing.Callable] = None) -> None: """Decorator. :param func: function to wrap @@ -81,9 +78,7 @@ def __init__( # pylint: enable=assigning-non-slot @property - def _func( - self - ) -> typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]]: + def _func(self) -> typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]]: """Get wrapped function. :rtype: typing.Optional[typing.Callable[..., typing.Union[typing.Awaitable, typing.Any]]] @@ -92,8 +87,7 @@ def _func( @abc.abstractmethod def _get_function_wrapper( - self, - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] ) -> typing.Callable: """Here should be constructed and returned real decorator. @@ -105,10 +99,7 @@ def _get_function_wrapper( def __call__( self, - *args: typing.Union[ - typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], - typing.Any - ], + *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Any: """Main decorator getter.""" @@ -129,11 +120,9 @@ def _await_if_required( target: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] ) -> typing.Callable[..., typing.Any]: """Await result if coroutine was returned.""" + @functools.wraps(target) - def wrapper( - *args, # type: typing.Any - **kwargs # type: typing.Any - ) -> typing.Any: + def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> typing.Any """Decorator/wrapper.""" result = target(*args, **kwargs) if asyncio.iscoroutine(result): @@ -147,9 +136,7 @@ def wrapper( def __repr__(self) -> str: """For debug purposes.""" return "<{cls}({func!r}) at 0x{id:X}>".format( - cls=self.__class__.__name__, - func=self.__func, - id=id(self) + cls=self.__class__.__name__, func=self.__func, id=id(self) ) # pragma: no cover @@ -157,4 +144,5 @@ def __repr__(self) -> str: if __name__ == '__main__': import doctest # pragma: no cover + doctest.testmod(verbose=True) # pragma: no cover diff --git a/threaded/_gthreadpooled.py b/threaded/_gthreadpooled.py index 4fda96b..4e2cdd1 100644 --- a/threaded/_gthreadpooled.py +++ b/threaded/_gthreadpooled.py @@ -26,10 +26,7 @@ from . import _base_threaded -__all__ = ( - 'GThreadPooled', - 'gthreadpooled', -) +__all__ = ('GThreadPooled', 'gthreadpooled') class GThreadPooled(_base_threaded.APIPooled): @@ -43,7 +40,7 @@ class GThreadPooled(_base_threaded.APIPooled): def configure( # pylint: disable=arguments-differ cls: typing.Type['GThreadPooled'], max_workers: typing.Optional[int] = None, - hub: typing.Optional[gevent.hub.Hub] = None + hub: typing.Optional[gevent.hub.Hub] = None, ) -> None: """Pool executor create and configure. @@ -64,10 +61,7 @@ def configure( # pylint: disable=arguments-differ # Hub change. Very special case. cls.__executor.kill() # pragma: no cover - cls.__executor = gevent.threadpool.ThreadPool( - maxsize=max_workers, - hub=hub - ) + cls.__executor = gevent.threadpool.ThreadPool(maxsize=max_workers, hub=hub) @classmethod def shutdown(cls: typing.Type['GThreadPooled']) -> None: @@ -89,8 +83,7 @@ def executor(self) -> gevent.threadpool.ThreadPool: return self.__executor def _get_function_wrapper( - self, - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] ) -> typing.Callable[..., gevent.event.AsyncResult]: """Here should be constructed and returned real decorator. @@ -103,20 +96,14 @@ def _get_function_wrapper( # noinspection PyMissingOrEmptyDocstring @functools.wraps(prepared) # pylint: disable=missing-docstring - def wrapper( - *args, # type: typing.Any - **kwargs # type: typing.Any - ) -> gevent.event.AsyncResult: + def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> gevent.event.AsyncResult return self.executor.spawn(prepared, *args, **kwargs) return wrapper def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[ - typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], - typing.Any - ], + *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[gevent.event.AsyncResult, typing.Callable[..., gevent.event.AsyncResult]]: """Callable instance.""" @@ -152,4 +139,6 @@ def gthreadpooled( # noqa: F811 if func is None: return GThreadPooled(func=func) return GThreadPooled(func=None)(func) + + # pylint: enable=function-redefined diff --git a/threaded/_threaded.py b/threaded/_threaded.py index 6e3bde7..d5ade17 100644 --- a/threaded/_threaded.py +++ b/threaded/_threaded.py @@ -23,28 +23,18 @@ from . import _class_decorator -__all__ = ( - 'Threaded', - 'threaded', -) +__all__ = ('Threaded', 'threaded') class Threaded(_class_decorator.BaseDecorator): """Run function in separate thread.""" - __slots__ = ( - '__name', - '__daemon', - '__started', - ) + __slots__ = ('__name', '__daemon', '__started') def __init__( self, name: typing.Optional[ - typing.Union[ - str, - typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] - ] + typing.Union[str, typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] ] = None, daemon: bool = False, started: bool = False, @@ -102,15 +92,11 @@ def __repr__(self) -> str: "name={self.name!r}, " "daemon={self.daemon!r}, " "started={self.started!r}, " - ")".format( - cls=self.__class__.__name__, - self=self, - ) + ")".format(cls=self.__class__.__name__, self=self) ) # pragma: no cover def _get_function_wrapper( - self, - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] ) -> typing.Callable[..., threading.Thread]: """Here should be constructed and returned real decorator. @@ -122,25 +108,12 @@ def _get_function_wrapper( prepared = self._await_if_required(func) name = self.name if name is None: - name = 'Threaded: ' + getattr( - func, - '__name__', - str(hash(func)) - ) + name = 'Threaded: ' + getattr(func, '__name__', str(hash(func))) # noinspection PyMissingOrEmptyDocstring @functools.wraps(prepared) # pylint: disable=missing-docstring - def wrapper( - *args, # type: typing.Any - **kwargs # type: typing.Any - ) -> threading.Thread: - thread = threading.Thread( - target=prepared, - name=name, - args=args, - kwargs=kwargs, - daemon=self.daemon - ) + def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> threading.Thread + thread = threading.Thread(target=prepared, name=name, args=args, kwargs=kwargs, daemon=self.daemon) if self.started: thread.start() return thread @@ -149,10 +122,7 @@ def wrapper( def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[ - typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], - typing.Any - ], + *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[threading.Thread, typing.Callable[..., threading.Thread]]: """Executable instance.""" @@ -162,29 +132,21 @@ def __call__( # pylint: disable=useless-super-delegation # pylint: disable=function-redefined, unused-argument @typing.overload def threaded( - name: typing.Callable, - daemon: bool = False, - started: bool = False + name: typing.Callable, daemon: bool = False, started: bool = False ) -> typing.Callable[..., threading.Thread]: """Overload: Call decorator without arguments.""" pass # pragma: no cover @typing.overload # noqa: F811 -def threaded( - name: typing.Optional[str] = None, - daemon: bool = False, - started: bool = False -) -> Threaded: +def threaded(name: typing.Optional[str] = None, daemon: bool = False, started: bool = False) -> Threaded: """Overload: Name is not callable.""" pass # pragma: no cover # pylint: enable=unused-argument def threaded( # noqa: F811 - name: typing.Optional[typing.Union[str, typing.Callable]] = None, - daemon: bool = False, - started: bool = False + name: typing.Optional[typing.Union[str, typing.Callable]] = None, daemon: bool = False, started: bool = False ) -> typing.Union[Threaded, typing.Callable[..., threading.Thread]]: """Run function in separate thread. @@ -200,10 +162,9 @@ def threaded( # noqa: F811 :rtype: typing.Union[Threaded, typing.Callable[..., threading.Thread]] """ if callable(name): - func, name = ( - name, - 'Threaded: ' + getattr(name, '__name__', str(hash(name))) - ) + func, name = (name, 'Threaded: ' + getattr(name, '__name__', str(hash(name)))) return Threaded(name=name, daemon=daemon, started=started)(func) # type: ignore return Threaded(name=name, daemon=daemon, started=started) + + # pylint: enable=function-redefined diff --git a/threaded/_threadpooled.py b/threaded/_threadpooled.py index da01ac1..868c94a 100644 --- a/threaded/_threadpooled.py +++ b/threaded/_threadpooled.py @@ -25,27 +25,18 @@ from . import _base_threaded -__all__ = ( - 'ThreadPooled', - 'threadpooled', -) +__all__ = ('ThreadPooled', 'threadpooled') class ThreadPooled(_base_threaded.APIPooled): """Post function to ThreadPoolExecutor.""" - __slots__ = ( - '__loop_getter', - '__loop_getter_need_context' - ) + __slots__ = ('__loop_getter', '__loop_getter_need_context') __executor = None # type: typing.Optional[ThreadPoolExecutor] @classmethod - def configure( - cls: typing.Type['ThreadPooled'], - max_workers: typing.Optional[int] = None, - ) -> None: + def configure(cls: typing.Type['ThreadPooled'], max_workers: typing.Optional[int] = None) -> None: """Pool executor create and configure. :param max_workers: Maximum workers @@ -56,9 +47,7 @@ def configure( return cls.__executor.shutdown() - cls.__executor = ThreadPoolExecutor( - max_workers=max_workers, - ) + cls.__executor = ThreadPoolExecutor(max_workers=max_workers) @classmethod def shutdown(cls: typing.Type['ThreadPooled']) -> None: @@ -81,10 +70,7 @@ def __init__( func: typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] = None, *, loop_getter: typing.Optional[ - typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ] + typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] ] = None, loop_getter_need_context: bool = False ) -> None: @@ -108,12 +94,7 @@ def __init__( @property def loop_getter( self - ) -> typing.Optional[ - typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ] - ]: + ) -> typing.Optional[typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop]]: """Loop getter. :rtype: typing.Union[None, typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] @@ -128,11 +109,7 @@ def loop_getter_need_context(self) -> bool: """ return self.__loop_getter_need_context - def _get_loop( - self, - *args: typing.Any, - **kwargs: typing.Any - ) -> typing.Optional[asyncio.AbstractEventLoop]: + def _get_loop(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Optional[asyncio.AbstractEventLoop]: """Get event loop in decorator class.""" if callable(self.loop_getter): if self.loop_getter_need_context: @@ -141,8 +118,7 @@ def _get_loop( return self.loop_getter def _get_function_wrapper( - self, - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] ) -> typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']]: """Here should be constructed and returned real decorator. @@ -156,37 +132,29 @@ def _get_function_wrapper( # noinspection PyMissingOrEmptyDocstring @functools.wraps(prepared) # pylint: disable=missing-docstring def wrapper( - *args: typing.Any, - **kwargs: typing.Any + *args: typing.Any, **kwargs: typing.Any ) -> typing.Union[ - concurrent.futures.Future, 'typing.Awaitable', - typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']] + concurrent.futures.Future, + 'typing.Awaitable', + typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']], ]: loop = self._get_loop(*args, **kwargs) if loop is None: return self.executor.submit(prepared, *args, **kwargs) - return loop.run_in_executor( - self.executor, - functools.partial( - prepared, - *args, **kwargs - ) - ) + return loop.run_in_executor(self.executor, functools.partial(prepared, *args, **kwargs)) return wrapper def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[ - typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], - typing.Any - ], + *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[ - concurrent.futures.Future, 'typing.Awaitable', - typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']] + concurrent.futures.Future, + 'typing.Awaitable', + typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']], ]: """Callable instance.""" return super(ThreadPooled, self).__call__(*args, **kwargs) # type: ignore @@ -198,12 +166,7 @@ def __repr__(self) -> str: "{func!r}, " "loop_getter={self.loop_getter!r}, " "loop_getter_need_context={self.loop_getter_need_context!r}, " - ") at 0x{id:X}>".format( - cls=self.__class__.__name__, - func=self._func, - self=self, - id=id(self) - ) + ") at 0x{id:X}>".format(cls=self.__class__.__name__, func=self._func, self=self, id=id(self)) ) # pragma: no cover @@ -223,10 +186,7 @@ def threadpooled( def threadpooled( func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], *, - loop_getter: typing.Union[ - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ], + loop_getter: typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop], loop_getter_need_context: bool = False ) -> typing.Callable[..., asyncio.Task]: """Overload: function callable, loop getter available.""" @@ -237,11 +197,7 @@ def threadpooled( def threadpooled( func: None = None, *, - loop_getter: typing.Union[ - None, - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ] = None, + loop_getter: typing.Union[None, typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] = None, loop_getter_need_context: bool = False ) -> ThreadPooled: """Overload: No function.""" @@ -252,16 +208,9 @@ def threadpooled( def threadpooled( # noqa: F811 func: typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] = None, *, - loop_getter: typing.Union[ - None, - typing.Callable[..., asyncio.AbstractEventLoop], - asyncio.AbstractEventLoop - ] = None, + loop_getter: typing.Union[None, typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] = None, loop_getter_need_context: bool = False -) -> typing.Union[ - ThreadPooled, - typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']] -]: +) -> typing.Union[ThreadPooled, typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']]]: """Post function to ThreadPoolExecutor. :param func: function to wrap @@ -278,16 +227,12 @@ def threadpooled( # noqa: F811 :rtype: typing.Union[ThreadPooled, typing.Callable[..., typing.Union[concurrent.futures.Future, typing.Awaitable]]] """ if func is None: - return ThreadPooled( - func=func, - loop_getter=loop_getter, - loop_getter_need_context=loop_getter_need_context - ) + return ThreadPooled(func=func, loop_getter=loop_getter, loop_getter_need_context=loop_getter_need_context) return ThreadPooled( # type: ignore - func=None, - loop_getter=loop_getter, - loop_getter_need_context=loop_getter_need_context + func=None, loop_getter=loop_getter, loop_getter_need_context=loop_getter_need_context )(func) + + # pylint: enable=function-redefined @@ -299,10 +244,7 @@ class ThreadPoolExecutor(concurrent.futures.ThreadPoolExecutor): __slots__ = () - def __init__( - self, - max_workers: typing.Optional[int] = None - ) -> None: + def __init__(self, max_workers: typing.Optional[int] = None) -> None: """Override init due to difference between Python <3.5 and 3.5+. :param max_workers: Maximum workers allowed. If none: cpu_count() or 1) * 5 @@ -310,12 +252,7 @@ def __init__( """ if max_workers is None: # Use 3.5+ behavior max_workers = (os.cpu_count() or 1) * 5 - super( - ThreadPoolExecutor, - self - ).__init__( - max_workers=max_workers, - ) + super(ThreadPoolExecutor, self).__init__(max_workers=max_workers) @property def max_workers(self) -> int: diff --git a/tox.ini b/tox.ini index c49ddf3..d25d7cb 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ [tox] minversion = 2.0 -envlist = pep8, pylint, mypy, bandit, pep257, py{34,35,36,37,py3}, docs, py{34,35,36,37}-nocov +envlist = black, pep8, pylint, mypy, bandit, pep257, py{34,35,36,37,py3}, docs, py{34,35,36,37}-nocov skipsdist = True skip_missing_interpreters = True @@ -100,13 +100,23 @@ exclude = __init__.py, docs ignore = + E203 +# whitespace before ':' show-pep8 = True show-source = True count = True max-line-length = 120 [pydocstyle] -ignore = D401, D203, D213 +ignore = + D401, + D202, + D203, + D213 +# First line should be in imperative mood; try rephrasing +# No blank lines allowed after function docstring +# 1 blank line required before class docstring +# Multi-line docstring summary should start at the second line [testenv:docs] deps = @@ -130,8 +140,15 @@ deps = pipdeptree commands = pipdeptree +[testenv:black] +deps = + black +usedevelop = False +commands = + black threaded + [testenv:mypy] deps = - mypy>=0.620 + mypy>=0.630 -r{toxinidir}/CI_REQUIREMENTS.txt commands = mypy --strict threaded From 70a54675080a9ebba72e8d2e4f02a0c11202663b Mon Sep 17 00:00:00 2001 From: Alexey Stepanov Date: Fri, 21 Sep 2018 14:52:32 +0200 Subject: [PATCH 2/2] Normalize strings Not documented, but postponed types evaluation also works with `"` Signed-off-by: Alexey Stepanov --- pyproject.toml | 1 - setup.py | 87 ++++++++++--------- .../test_gevent_threadpooled_async.py | 2 +- test/async_syntax/test_pooled_async.py | 8 +- test/test_gevent_threadpooled.py | 2 +- test/test_pooled_coroutine.py | 8 +- test/test_threaded.py | 12 +-- threaded/__init__.py | 26 +++--- threaded/_asynciotask.py | 14 +-- threaded/_base_threaded.py | 6 +- threaded/_class_decorator.py | 10 +-- threaded/_gthreadpooled.py | 14 +-- threaded/_threaded.py | 16 ++-- threaded/_threadpooled.py | 34 ++++---- 14 files changed, 120 insertions(+), 120 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1cf2044..708fb53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,5 +8,4 @@ requires = [ [tool.black] line-length = 120 -skip-string-normalization = true safe = true diff --git a/setup.py b/setup.py index d4131c2..11baba6 100644 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ try: # noinspection PyPackageRequirements from Cython.Build import cythonize + # noinspection PyPackageRequirements import gevent except ImportError: @@ -32,32 +33,32 @@ import setuptools -with open(os.path.join(os.path.dirname(__file__), 'threaded', '__init__.py')) as f: +with open(os.path.join(os.path.dirname(__file__), "threaded", "__init__.py")) as f: source = f.read() -with open('requirements.txt') as f: +with open("requirements.txt") as f: required = f.read().splitlines() -with open('README.rst') as f: +with open("README.rst") as f: long_description = f.read() def _extension(modpath): """Make setuptools.Extension.""" - return setuptools.Extension(modpath, [modpath.replace('.', '/') + '.py']) + return setuptools.Extension(modpath, [modpath.replace(".", "/") + ".py"]) requires_optimization = [ - _extension('threaded._class_decorator'), - _extension('threaded._base_threaded'), - _extension('threaded._asynciotask'), - _extension('threaded._threaded'), - _extension('threaded._threadpooled'), - _extension('threaded._gthreadpooled'), + _extension("threaded._class_decorator"), + _extension("threaded._base_threaded"), + _extension("threaded._asynciotask"), + _extension("threaded._threaded"), + _extension("threaded._threadpooled"), + _extension("threaded._gthreadpooled"), ] -if 'win32' != sys.platform: - requires_optimization.append(_extension('threaded.__init__')) +if "win32" != sys.platform: + requires_optimization.append(_extension("threaded.__init__")) # noinspection PyCallingNonCallable ext_modules = ( @@ -88,10 +89,10 @@ def run(self): # Copy __init__.py back to repair package. build_dir = os.path.abspath(self.build_lib) - root_dir = os.path.abspath(os.path.join(__file__, '..')) + root_dir = os.path.abspath(os.path.join(__file__, "..")) target_dir = build_dir if not self.inplace else root_dir - src_file = os.path.join('threaded', '__init__.py') + src_file = os.path.join("threaded", "__init__.py") src = os.path.join(root_dir, src_file) dst = os.path.join(target_dir, src_file) @@ -100,7 +101,7 @@ def run(self): shutil.copyfile(src, dst) except ( distutils.errors.DistutilsPlatformError, - getattr(globals()['__builtins__'], 'FileNotFoundError', OSError), + getattr(globals()["__builtins__"], "FileNotFoundError", OSError), ): raise BuildFailed() @@ -193,35 +194,35 @@ def get_simple_vars_from_src(src): variables = get_simple_vars_from_src(source) classifiers = [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", ] -keywords = ['pooling', 'multithreading', 'threading', 'asyncio', 'gevent', 'development'] +keywords = ["pooling", "multithreading", "threading", "asyncio", "gevent", "development"] setup_args = dict( - name='threaded', - author=variables['__author__'], - author_email=variables['__author_email__'], - maintainer=', '.join( - '{name} <{email}>'.format(name=name, email=email) for name, email in variables['__maintainers__'].items() + name="threaded", + author=variables["__author__"], + author_email=variables["__author_email__"], + maintainer=", ".join( + "{name} <{email}>".format(name=name, email=email) for name, email in variables["__maintainers__"].items() ), - url=variables['__url__'], - version=variables['__version__'], - license=variables['__license__'], - description=variables['__description__'], + url=variables["__url__"], + version=variables["__version__"], + license=variables["__license__"], + description=variables["__description__"], long_description=long_description, classifiers=classifiers, keywords=keywords, - python_requires='>=3.4', + python_requires=">=3.4", # While setuptools cannot deal with pre-installed incompatible versions, # setting a lower bound is not harmful - it makes error messages cleaner. DO # NOT set an upper bound on setuptools, as that will lead to uninstallable @@ -231,18 +232,18 @@ def get_simple_vars_from_src(src): setup_requires="setuptools >= 21.0.0,!=24.0.0," "!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2," "!=36.2.0", - extras_require={'gevent': ['gevent >= 1.2.2']}, + extras_require={"gevent": ["gevent >= 1.2.2"]}, install_requires=required, - package_data={'threaded': ['py.typed']}, + package_data={"threaded": ["py.typed"]}, ) if cythonize is not None: - setup_args['ext_modules'] = ext_modules - setup_args['cmdclass'] = dict(build_ext=AllowFailRepair) + setup_args["ext_modules"] = ext_modules + setup_args["cmdclass"] = dict(build_ext=AllowFailRepair) try: setuptools.setup(**setup_args) except BuildFailed: - print('*' * 80 + '\n' '* Build Failed!\n' '* Use clear scripts version.\n' '*' * 80 + '\n') - del setup_args['ext_modules'] - del setup_args['cmdclass'] + print("*" * 80 + "\n" "* Build Failed!\n" "* Use clear scripts version.\n" "*" * 80 + "\n") + del setup_args["ext_modules"] + del setup_args["cmdclass"] setuptools.setup(**setup_args) diff --git a/test/async_syntax/test_gevent_threadpooled_async.py b/test/async_syntax/test_gevent_threadpooled_async.py index 087c08d..e7f6f5e 100644 --- a/test/async_syntax/test_gevent_threadpooled_async.py +++ b/test/async_syntax/test_gevent_threadpooled_async.py @@ -24,7 +24,7 @@ import threaded -@unittest.skipIf(gevent is None, 'No gevent') +@unittest.skipIf(gevent is None, "No gevent") class TestThreadPooled(unittest.TestCase): def tearDown(self): threaded.GThreadPooled.shutdown() diff --git a/test/async_syntax/test_pooled_async.py b/test/async_syntax/test_pooled_async.py index 91a67cb..f5a0cc6 100644 --- a/test/async_syntax/test_pooled_async.py +++ b/test/async_syntax/test_pooled_async.py @@ -78,17 +78,17 @@ class TestAsyncIOTask(unittest.TestCase): def test_default(self): @threaded.asynciotask async def test(): - return 'test' + return "test" loop = asyncio.get_event_loop() res = loop.run_until_complete(asyncio.wait_for(test(), 1)) - self.assertEqual(res, 'test') + self.assertEqual(res, "test") def test_construct(self): @threaded.asynciotask() async def test(): - return 'test' + return "test" loop = asyncio.get_event_loop() res = loop.run_until_complete(asyncio.wait_for(test(), 1)) - self.assertEqual(res, 'test') + self.assertEqual(res, "test") diff --git a/test/test_gevent_threadpooled.py b/test/test_gevent_threadpooled.py index 6cd3e8b..369cfff 100644 --- a/test/test_gevent_threadpooled.py +++ b/test/test_gevent_threadpooled.py @@ -25,7 +25,7 @@ import threaded -@unittest.skipIf(gevent is None, 'No gevent') +@unittest.skipIf(gevent is None, "No gevent") class TestThreadPooled(unittest.TestCase): def tearDown(self): threaded.GThreadPooled.shutdown() diff --git a/test/test_pooled_coroutine.py b/test/test_pooled_coroutine.py index 4e97b78..02e111c 100644 --- a/test/test_pooled_coroutine.py +++ b/test/test_pooled_coroutine.py @@ -84,18 +84,18 @@ def test_default(self): @threaded.asynciotask @asyncio.coroutine def test(): - return 'test' + return "test" loop = asyncio.get_event_loop() res = loop.run_until_complete(asyncio.wait_for(test(), 1)) - self.assertEqual(res, 'test') + self.assertEqual(res, "test") def test_construct(self): @threaded.asynciotask() @asyncio.coroutine def test(): - return 'test' + return "test" loop = asyncio.get_event_loop() res = loop.run_until_complete(asyncio.wait_for(test(), 1)) - self.assertEqual(res, 'test') + self.assertEqual(res, "test") diff --git a/test/test_threaded.py b/test/test_threaded.py index 2fc3ab7..2b11f9f 100644 --- a/test/test_threaded.py +++ b/test/test_threaded.py @@ -27,7 +27,7 @@ def func_test(): # pylint: disable=assignment-from-no-return test_thread = func_test() # pylint: enable=assignment-from-no-return - self.assertEqual(test_thread.name, 'Threaded: func_test') + self.assertEqual(test_thread.name, "Threaded: func_test") self.assertFalse(test_thread.daemon) self.assertFalse(test_thread.isAlive()) @@ -39,19 +39,19 @@ def func_test(): # pylint: disable=assignment-from-no-return test_thread = func_test() # pylint: enable=assignment-from-no-return - self.assertEqual(test_thread.name, 'Threaded: func_test') + self.assertEqual(test_thread.name, "Threaded: func_test") self.assertFalse(test_thread.daemon) self.assertFalse(test_thread.isAlive()) def test_name(self): - @threaded.threaded(name='test name') + @threaded.threaded(name="test name") def func_test(): pass # pylint: disable=assignment-from-no-return test_thread = func_test() # pylint: enable=assignment-from-no-return - self.assertEqual(test_thread.name, 'test name') + self.assertEqual(test_thread.name, "test name") self.assertFalse(test_thread.daemon) self.assertFalse(test_thread.isAlive()) @@ -63,11 +63,11 @@ def func_test(): # pylint: disable=assignment-from-no-return test_thread = func_test() # pylint: enable=assignment-from-no-return - self.assertEqual(test_thread.name, 'Threaded: func_test') + self.assertEqual(test_thread.name, "Threaded: func_test") self.assertTrue(test_thread.daemon) self.assertFalse(test_thread.isAlive()) - @mock.patch('threading.Thread', autospec=True) + @mock.patch("threading.Thread", autospec=True) def test_started(self, thread): @threaded.threaded(started=True) def func_test(): diff --git a/threaded/__init__.py b/threaded/__init__.py index 48ca8c1..51baa69 100644 --- a/threaded/__init__.py +++ b/threaded/__init__.py @@ -30,25 +30,25 @@ __all__ = ( - 'ThreadPooled', - 'Threaded', - 'threadpooled', - 'threaded', - 'AsyncIOTask', - 'asynciotask', + "ThreadPooled", + "Threaded", + "threadpooled", + "threaded", + "AsyncIOTask", + "asynciotask", ) # type: typing.Tuple[str, ...] if GThreadPooled is not None: # pragma: no cover - __all__ += ('GThreadPooled', 'gthreadpooled') + __all__ += ("GThreadPooled", "gthreadpooled") -__version__ = '2.0.2' +__version__ = "2.0.2" __author__ = "Alexey Stepanov" -__author_email__ = 'penguinolog@gmail.com' +__author_email__ = "penguinolog@gmail.com" __maintainers__ = { - 'Alexey Stepanov': 'penguinolog@gmail.com', - 'Antonio Esposito': 'esposito.cloud@gmail.com', - 'Dennis Dmitriev': 'dis-xcom@gmail.com', + "Alexey Stepanov": "penguinolog@gmail.com", + "Antonio Esposito": "esposito.cloud@gmail.com", + "Dennis Dmitriev": "dis-xcom@gmail.com", } -__url__ = 'https://github.com/python-useful-helpers/threaded' +__url__ = "https://github.com/python-useful-helpers/threaded" __description__ = "Decorators for running functions in Thread/ThreadPool/IOLoop" __license__ = "Apache License, Version 2.0" diff --git a/threaded/_asynciotask.py b/threaded/_asynciotask.py index 5776b20..77834a8 100644 --- a/threaded/_asynciotask.py +++ b/threaded/_asynciotask.py @@ -20,17 +20,17 @@ from . import _class_decorator -__all__ = ('AsyncIOTask', 'asynciotask') +__all__ = ("AsyncIOTask", "asynciotask") class AsyncIOTask(_class_decorator.BaseDecorator): """Wrap to asyncio.Task.""" - __slots__ = ('__loop_getter', '__loop_getter_need_context') + __slots__ = ("__loop_getter", "__loop_getter_need_context") def __init__( self, - func: typing.Optional[typing.Callable[..., 'typing.Awaitable']] = None, + func: typing.Optional[typing.Callable[..., "typing.Awaitable"]] = None, *, loop_getter: typing.Union[ typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop @@ -78,7 +78,7 @@ def get_loop(self, *args, **kwargs): # type: (typing.Any, typing.Any) -> asynci return self.loop_getter def _get_function_wrapper( - self, func: typing.Callable[..., 'typing.Awaitable'] + self, func: typing.Callable[..., "typing.Awaitable"] ) -> typing.Callable[..., asyncio.Task]: """Here should be constructed and returned real decorator. @@ -96,7 +96,7 @@ def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> asyncio.Task return wrapper def __call__( # pylint: disable=useless-super-delegation - self, *args: typing.Union[typing.Callable[..., 'typing.Awaitable'], typing.Any], **kwargs: typing.Any + self, *args: typing.Union[typing.Callable[..., "typing.Awaitable"], typing.Any], **kwargs: typing.Any ) -> typing.Union[asyncio.Task, typing.Callable[..., asyncio.Task]]: """Callable instance.""" return super(AsyncIOTask, self).__call__(*args, **kwargs) # type: ignore @@ -128,7 +128,7 @@ def asynciotask( @typing.overload # noqa: F811 def asynciotask( - func: typing.Callable[..., 'typing.Awaitable'], + func: typing.Callable[..., "typing.Awaitable"], *, loop_getter: typing.Union[ typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop @@ -141,7 +141,7 @@ def asynciotask( # pylint: enable=unused-argument def asynciotask( # noqa: F811 - func: typing.Optional[typing.Callable[..., 'typing.Awaitable']] = None, + func: typing.Optional[typing.Callable[..., "typing.Awaitable"]] = None, *, loop_getter: typing.Union[ typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop diff --git a/threaded/_base_threaded.py b/threaded/_base_threaded.py index 5bf5cd6..55a09f2 100644 --- a/threaded/_base_threaded.py +++ b/threaded/_base_threaded.py @@ -20,7 +20,7 @@ from . import _class_decorator -__all__ = ('APIPooled',) +__all__ = ("APIPooled",) class APIPooled(_class_decorator.BaseDecorator, metaclass=abc.ABCMeta): @@ -32,7 +32,7 @@ class APIPooled(_class_decorator.BaseDecorator, metaclass=abc.ABCMeta): @classmethod @abc.abstractmethod - def configure(cls: typing.Type['APIPooled'], max_workers: typing.Optional[int] = None) -> None: + def configure(cls: typing.Type["APIPooled"], max_workers: typing.Optional[int] = None) -> None: """Pool executor create and configure. :param max_workers: Maximum workers @@ -42,7 +42,7 @@ def configure(cls: typing.Type['APIPooled'], max_workers: typing.Optional[int] = @classmethod @abc.abstractmethod - def shutdown(cls: typing.Type['APIPooled']) -> None: + def shutdown(cls: typing.Type["APIPooled"]) -> None: """Shutdown executor.""" raise NotImplementedError() # pragma: no cover diff --git a/threaded/_class_decorator.py b/threaded/_class_decorator.py index 2135583..9bf0d02 100644 --- a/threaded/_class_decorator.py +++ b/threaded/_class_decorator.py @@ -78,7 +78,7 @@ def __init__(self, func: typing.Optional[typing.Callable] = None) -> None: # pylint: enable=assigning-non-slot @property - def _func(self) -> typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]]: + def _func(self) -> typing.Optional[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]]]: """Get wrapped function. :rtype: typing.Optional[typing.Callable[..., typing.Union[typing.Awaitable, typing.Any]]] @@ -87,7 +87,7 @@ def _func(self) -> typing.Optional[typing.Callable[..., typing.Union['typing.Awa @abc.abstractmethod def _get_function_wrapper( - self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] ) -> typing.Callable: """Here should be constructed and returned real decorator. @@ -99,7 +99,7 @@ def _get_function_wrapper( def __call__( self, - *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], + *args: typing.Union[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Any: """Main decorator getter.""" @@ -117,7 +117,7 @@ def __call__( @staticmethod def _await_if_required( - target: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + target: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] ) -> typing.Callable[..., typing.Any]: """Await result if coroutine was returned.""" @@ -142,7 +142,7 @@ def __repr__(self) -> str: # 8<---------------------------------------------------------------------------- -if __name__ == '__main__': +if __name__ == "__main__": import doctest # pragma: no cover doctest.testmod(verbose=True) # pragma: no cover diff --git a/threaded/_gthreadpooled.py b/threaded/_gthreadpooled.py index 4e2cdd1..88c1ed8 100644 --- a/threaded/_gthreadpooled.py +++ b/threaded/_gthreadpooled.py @@ -26,7 +26,7 @@ from . import _base_threaded -__all__ = ('GThreadPooled', 'gthreadpooled') +__all__ = ("GThreadPooled", "gthreadpooled") class GThreadPooled(_base_threaded.APIPooled): @@ -38,7 +38,7 @@ class GThreadPooled(_base_threaded.APIPooled): @classmethod def configure( # pylint: disable=arguments-differ - cls: typing.Type['GThreadPooled'], + cls: typing.Type["GThreadPooled"], max_workers: typing.Optional[int] = None, hub: typing.Optional[gevent.hub.Hub] = None, ) -> None: @@ -64,7 +64,7 @@ def configure( # pylint: disable=arguments-differ cls.__executor = gevent.threadpool.ThreadPool(maxsize=max_workers, hub=hub) @classmethod - def shutdown(cls: typing.Type['GThreadPooled']) -> None: + def shutdown(cls: typing.Type["GThreadPooled"]) -> None: """Shutdown executor. Due to not implemented method, set maxsize to 0 (do not accept new). @@ -83,7 +83,7 @@ def executor(self) -> gevent.threadpool.ThreadPool: return self.__executor def _get_function_wrapper( - self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] ) -> typing.Callable[..., gevent.event.AsyncResult]: """Here should be constructed and returned real decorator. @@ -103,7 +103,7 @@ def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> gevent.event. def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], + *args: typing.Union[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[gevent.event.AsyncResult, typing.Callable[..., gevent.event.AsyncResult]]: """Callable instance.""" @@ -113,7 +113,7 @@ def __call__( # pylint: disable=useless-super-delegation # pylint: disable=function-redefined, unused-argument @typing.overload def gthreadpooled( - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] ) -> typing.Callable[..., gevent.event.AsyncResult]: """Overloaded: func provided.""" pass # pragma: no cover @@ -127,7 +127,7 @@ def gthreadpooled(func: None = None) -> GThreadPooled: # pylint: enable=unused-argument def gthreadpooled( # noqa: F811 - func: typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] = None + func: typing.Optional[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]]] = None ) -> typing.Union[GThreadPooled, typing.Callable[..., gevent.event.AsyncResult]]: """Post function to gevent.threadpool.ThreadPool. diff --git a/threaded/_threaded.py b/threaded/_threaded.py index d5ade17..9798892 100644 --- a/threaded/_threaded.py +++ b/threaded/_threaded.py @@ -23,18 +23,18 @@ from . import _class_decorator -__all__ = ('Threaded', 'threaded') +__all__ = ("Threaded", "threaded") class Threaded(_class_decorator.BaseDecorator): """Run function in separate thread.""" - __slots__ = ('__name', '__daemon', '__started') + __slots__ = ("__name", "__daemon", "__started") def __init__( self, name: typing.Optional[ - typing.Union[str, typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] + typing.Union[str, typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]]] ] = None, daemon: bool = False, started: bool = False, @@ -55,7 +55,7 @@ def __init__( self.__started = started if callable(name): func = name # type: typing.Callable - self.__name = 'Threaded: ' + getattr(name, '__name__', str(hash(name))) # type: str + self.__name = "Threaded: " + getattr(name, "__name__", str(hash(name))) # type: str else: func, self.__name = None, name # type: ignore super(Threaded, self).__init__(func=func) @@ -96,7 +96,7 @@ def __repr__(self) -> str: ) # pragma: no cover def _get_function_wrapper( - self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] + self, func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] ) -> typing.Callable[..., threading.Thread]: """Here should be constructed and returned real decorator. @@ -108,7 +108,7 @@ def _get_function_wrapper( prepared = self._await_if_required(func) name = self.name if name is None: - name = 'Threaded: ' + getattr(func, '__name__', str(hash(func))) + name = "Threaded: " + getattr(func, "__name__", str(hash(func))) # noinspection PyMissingOrEmptyDocstring @functools.wraps(prepared) # pylint: disable=missing-docstring @@ -122,7 +122,7 @@ def wrapper(*args, **kwargs): # type: (typing.Any, typing.Any) -> threading.Thr def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], + *args: typing.Union[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[threading.Thread, typing.Callable[..., threading.Thread]]: """Executable instance.""" @@ -162,7 +162,7 @@ def threaded( # noqa: F811 :rtype: typing.Union[Threaded, typing.Callable[..., threading.Thread]] """ if callable(name): - func, name = (name, 'Threaded: ' + getattr(name, '__name__', str(hash(name)))) + func, name = (name, "Threaded: " + getattr(name, "__name__", str(hash(name)))) return Threaded(name=name, daemon=daemon, started=started)(func) # type: ignore return Threaded(name=name, daemon=daemon, started=started) diff --git a/threaded/_threadpooled.py b/threaded/_threadpooled.py index 868c94a..4b58246 100644 --- a/threaded/_threadpooled.py +++ b/threaded/_threadpooled.py @@ -25,18 +25,18 @@ from . import _base_threaded -__all__ = ('ThreadPooled', 'threadpooled') +__all__ = ("ThreadPooled", "threadpooled") class ThreadPooled(_base_threaded.APIPooled): """Post function to ThreadPoolExecutor.""" - __slots__ = ('__loop_getter', '__loop_getter_need_context') + __slots__ = ("__loop_getter", "__loop_getter_need_context") __executor = None # type: typing.Optional[ThreadPoolExecutor] @classmethod - def configure(cls: typing.Type['ThreadPooled'], max_workers: typing.Optional[int] = None) -> None: + def configure(cls: typing.Type["ThreadPooled"], max_workers: typing.Optional[int] = None) -> None: """Pool executor create and configure. :param max_workers: Maximum workers @@ -50,13 +50,13 @@ def configure(cls: typing.Type['ThreadPooled'], max_workers: typing.Optional[int cls.__executor = ThreadPoolExecutor(max_workers=max_workers) @classmethod - def shutdown(cls: typing.Type['ThreadPooled']) -> None: + def shutdown(cls: typing.Type["ThreadPooled"]) -> None: """Shutdown executor.""" if cls.__executor is not None: cls.__executor.shutdown() @property - def executor(self) -> 'ThreadPoolExecutor': + def executor(self) -> "ThreadPoolExecutor": """Executor instance. :rtype: ThreadPoolExecutor @@ -67,7 +67,7 @@ def executor(self) -> 'ThreadPoolExecutor': def __init__( self, - func: typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] = None, + func: typing.Optional[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]]] = None, *, loop_getter: typing.Optional[ typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] @@ -118,8 +118,8 @@ def _get_loop(self, *args: typing.Any, **kwargs: typing.Any) -> typing.Optional[ return self.loop_getter def _get_function_wrapper( - self, func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]] - ) -> typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']]: + self, func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]] + ) -> typing.Callable[..., typing.Union[concurrent.futures.Future, "typing.Awaitable"]]: """Here should be constructed and returned real decorator. :param func: Wrapped function @@ -135,8 +135,8 @@ def wrapper( *args: typing.Any, **kwargs: typing.Any ) -> typing.Union[ concurrent.futures.Future, - 'typing.Awaitable', - typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']], + "typing.Awaitable", + typing.Callable[..., typing.Union[concurrent.futures.Future, "typing.Awaitable"]], ]: loop = self._get_loop(*args, **kwargs) @@ -149,12 +149,12 @@ def wrapper( def __call__( # pylint: disable=useless-super-delegation self, - *args: typing.Union[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], typing.Any], + *args: typing.Union[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], typing.Any], **kwargs: typing.Any ) -> typing.Union[ concurrent.futures.Future, - 'typing.Awaitable', - typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']], + "typing.Awaitable", + typing.Callable[..., typing.Union[concurrent.futures.Future, "typing.Awaitable"]], ]: """Callable instance.""" return super(ThreadPooled, self).__call__(*args, **kwargs) # type: ignore @@ -173,7 +173,7 @@ def __repr__(self) -> str: # pylint: disable=function-redefined, unused-argument @typing.overload def threadpooled( - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], + func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], *, loop_getter: None = None, loop_getter_need_context: bool = False @@ -184,7 +184,7 @@ def threadpooled( @typing.overload # noqa: F811 def threadpooled( - func: typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]], + func: typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]], *, loop_getter: typing.Union[typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop], loop_getter_need_context: bool = False @@ -206,11 +206,11 @@ def threadpooled( # pylint: enable=unused-argument def threadpooled( # noqa: F811 - func: typing.Optional[typing.Callable[..., typing.Union['typing.Awaitable', typing.Any]]] = None, + func: typing.Optional[typing.Callable[..., typing.Union["typing.Awaitable", typing.Any]]] = None, *, loop_getter: typing.Union[None, typing.Callable[..., asyncio.AbstractEventLoop], asyncio.AbstractEventLoop] = None, loop_getter_need_context: bool = False -) -> typing.Union[ThreadPooled, typing.Callable[..., typing.Union[concurrent.futures.Future, 'typing.Awaitable']]]: +) -> typing.Union[ThreadPooled, typing.Callable[..., typing.Union[concurrent.futures.Future, "typing.Awaitable"]]]: """Post function to ThreadPoolExecutor. :param func: function to wrap