diff --git a/.travis.yml b/.travis.yml index d2360ac..448ff19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,40 @@ language: python os: linux install: - &upgrade_python_toolset pip install --upgrade pip setuptools wheel -- pip install tox -- pip install coveralls -script: [] +- pip install --upgrade pytest pytest-sugar +- &install_deps pip install -r CI_REQUIREMENTS.txt +- pip install --upgrade pytest-cov coveralls + +_python: +- &python27 + name: "Python 2.7" + python: 2.7 +- &pypy + name: "PyPy" + python: pypy +- &python37 + name: "Python 3.7" + python: 3.7 + dist: xenial + sudo: true + +_helpers: +- &build_package python setup.py bdist_wheel + +- &static_analysis + stage: Static analysis + <<: *python27 + after_success: skip + +- &code_style_check + stage: Code style check + <<: *python27 + after_success: skip + +script: +- pip install -e . +- py.test -vv --cov-config .coveragerc --cov-report= --cov=threaded test +- coverage report -m --fail-under 87 after_success: - coveralls @@ -13,79 +44,62 @@ jobs: fast_finish: true include: - stage: test - name: "Python 2.7" - python: 2.7 - script: - - tox -e py27 + <<: *python27 - stage: test - name: "PyPy" - python: pypy - script: - - tox -e pypy + <<: *pypy - - stage: Static analisys + - <<: *static_analysis name: "PyLint" - python: 2.7 - services: [] install: - *upgrade_python_toolset - - pip install tox + - *install_deps + - pip install --upgrade "pylint < 2.0" script: - - tox -e pylint - after_success: skip - - stage: Static analisys + - pylint threaded + - <<: *static_analysis name: "Bandit" - python: 2.7 - services: [] install: - *upgrade_python_toolset - - pip install tox + - pip install --upgrade bandit script: - - tox -e bandit - after_success: skip - - stage: Static analisys + - bandit -r threaded + - <<: *static_analysis + <<: *python37 name: "MyPy" - python: 3.7 - dist: xenial - sudo: true - services: [] install: - *upgrade_python_toolset - - pip install tox + - *install_deps + - pip install --upgrade "mypy >= 0.620" script: - - tox -e mypy - after_success: skip + - mypy --strict threaded - - stage: Code style check + - <<: *code_style_check name: "PEP8" - python: 2.7 install: - *upgrade_python_toolset - - pip install tox + - pip install --upgrade flake8 script: - - tox -e pep8 - after_success: skip - - stage: Code style check + - flake8 + - <<: *code_style_check name: "PEP257" - python: 2.7 install: - *upgrade_python_toolset - - pip install tox + - pip install --upgrade pydocstyle script: - - tox -e pep257 - after_success: skip + - pydocstyle threaded - stage: deploy # This prevents job from appearing in test plan unless commit is tagged: if: tag IS present - # Run on pypy to build not cythonized wheel - python: pypy + <<: *pypy + name: Build universal bdist_wheel. Deploy bdist and sdist. services: [] install: - *upgrade_python_toolset - pip install -r build_requirements.txt script: - - python setup.py bdist_wheel + - *build_package + before_deploy: [] deploy: - provider: pypi # `skip_cleanup: true` is required to preserve binary wheels, built diff --git a/CI_REQUIREMENTS.txt b/CI_REQUIREMENTS.txt index ec7b2d2..d5cc650 100644 --- a/CI_REQUIREMENTS.txt +++ b/CI_REQUIREMENTS.txt @@ -1,6 +1,7 @@ +six >=1.10.0 +futures>=3.1 ; python_version == "2.7" typing >= 3.6 ; python_version < "3.8" mock; python_version == "2.7" -futures>=3.1; python_version == "2.7" greenlet <= 0.4.13 gevent >= 1.2, <1.3.0 ; platform_python_implementation == "PyPy" gevent >= 1.2 ; platform_python_implementation != "PyPy" diff --git a/build_requirements.txt b/build_requirements.txt index 21ba7bb..5bf19d7 100644 --- a/build_requirements.txt +++ b/build_requirements.txt @@ -1,4 +1,3 @@ -Cython; platform_python_implementation == "CPython" wheel -r CI_REQUIREMENTS.txt -r requirements.txt diff --git a/setup.cfg b/setup.cfg index fc8c93b..a7c8525 100644 --- a/setup.cfg +++ b/setup.cfg @@ -38,11 +38,16 @@ exclude = __init__.py, docs ignore = +show-pep8 = True show-source = True count = True +max-line-length = 120 + +[pydocstyle] +ignore = D401, D203, D213 [aliases] test=pytest [tool:pytest] -addopts = -vv --cov-config .coveragerc --cov=threaded +addopts = -vvv -s -p no:django -p no:ipdb diff --git a/threaded/__init__.py b/threaded/__init__.py index 4e0faa2..8481155 100644 --- a/threaded/__init__.py +++ b/threaded/__init__.py @@ -33,7 +33,7 @@ __all__ = ( 'ThreadPooled', 'Threaded', - 'threadpooled', 'threaded' + 'threadpooled', 'threaded', ) # type: typing.Tuple[str, ...] if GThreadPooled is not None: # pragma: no cover diff --git a/threaded/_class_decorator.py b/threaded/_class_decorator.py index d27bf4f..97cf0ea 100644 --- a/threaded/_class_decorator.py +++ b/threaded/_class_decorator.py @@ -110,7 +110,7 @@ def _get_function_wrapper( def __call__( self, - *args, # type: typing.Any + *args, # type: typing.Union[typing.Callable, typing.Any] **kwargs # type: typing.Any ): # type: (...) -> typing.Any """Main decorator getter.""" diff --git a/threaded/_gthreadpooled.py b/threaded/_gthreadpooled.py index 70eb7cb..8df6c3a 100644 --- a/threaded/_gthreadpooled.py +++ b/threaded/_gthreadpooled.py @@ -40,9 +40,8 @@ class GThreadPooled(_base_threaded.APIPooled): __executor = None # type: typing.Optional[gevent.threadpool.ThreadPool] - # pylint: disable=arguments-differ @classmethod - def configure( + def configure( # pylint: disable=arguments-differ cls, # type: typing.Type[GThreadPooled] max_workers=None, # type: typing.Optional[int] hub=None # type: typing.Optional[gevent.hub.Hub] @@ -71,8 +70,6 @@ def configure( hub=hub ) - # pylint: enable=arguments-differ - @classmethod def shutdown(cls): # type: (typing.Type[GThreadPooled]) -> None """Shutdown executor. @@ -103,16 +100,14 @@ def _get_function_wrapper( :return: wrapped function :rtype: typing.Callable[..., gevent.event.AsyncResult] """ - # pylint: disable=missing-docstring # noinspection PyMissingOrEmptyDocstring @six.wraps(func) - def wrapper( + def wrapper( # pylint: disable=missing-docstring *args, # type: typing.Any **kwargs # type: typing.Any ): # type: (...) -> gevent.event.AsyncResult return self.executor.spawn(func, *args, **kwargs) - # pylint: enable=missing-docstring return wrapper def __call__( # pylint: disable=useless-super-delegation @@ -132,6 +127,7 @@ def gthreadpooled( :param func: function to wrap :type func: typing.Optional[typing.Callable] + :return: GThreadPooled instance, if called as function or argumented decorator, else callable wrapper :rtype: typing.Union[GThreadPooled, typing.Callable[..., gevent.event.AsyncResult]] """ if func is None: diff --git a/threaded/_threaded.py b/threaded/_threaded.py index 34b1f4a..a63140b 100644 --- a/threaded/_threaded.py +++ b/threaded/_threaded.py @@ -125,10 +125,9 @@ def _get_function_wrapper( str(hash(func)) ) - # pylint: disable=missing-docstring # noinspection PyMissingOrEmptyDocstring @six.wraps(func) - def wrapper( + def wrapper( # pylint: disable=missing-docstring *args, # type: typing.Any **kwargs # type: typing.Any ): # type: (...) -> threading.Thread @@ -143,7 +142,6 @@ def wrapper( thread.start() return thread - # pylint: enable=missing-docstring return wrapper def __call__( # pylint: disable=useless-super-delegation @@ -171,6 +169,7 @@ def threaded( :type daemon: bool :param started: Return started thread :type started: bool + :return: Threaded instance, if called as function or argumented decorator, else callable wraper :rtype: typing.Union[Threaded, typing.Callable[..., threading.Thread]] """ if callable(name): diff --git a/threaded/_threadpooled.py b/threaded/_threadpooled.py index 77a08d1..181029e 100644 --- a/threaded/_threadpooled.py +++ b/threaded/_threadpooled.py @@ -71,10 +71,7 @@ def executor(self): # type: () -> ThreadPoolExecutor :rtype: ThreadPoolExecutor """ - if ( - not isinstance(self.__executor, ThreadPoolExecutor) or - self.__executor.is_shutdown - ): + if not isinstance(self.__executor, ThreadPoolExecutor) or self.__executor.is_shutdown: self.configure() return self.__executor # type: ignore @@ -89,16 +86,14 @@ def _get_function_wrapper( :return: wrapped function :rtype: typing.Callable[..., concurrent.futures.Future] """ - # pylint: disable=missing-docstring # noinspection PyMissingOrEmptyDocstring @six.wraps(func) - def wrapper( + def wrapper( # pylint: disable=missing-docstring *args, # type: typing.Any **kwargs # type: typing.Any ): # type: (...) -> concurrent.futures.Future return self.executor.submit(func, *args, **kwargs) - # pylint: enable=missing-docstring return wrapper @@ -110,6 +105,7 @@ def threadpooled( :param func: function to wrap :type func: typing.Optional[typing.Callable] + :return: ThreadPooled instance, if called as function or argumented decorator, else callable wrapper :rtype: typing.Union[ThreadPooled, typing.Callable[..., concurrent.futures.Future]] """ if func is None: @@ -132,8 +128,7 @@ def __init__( ): # type: (...) -> 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 + :param max_workers: Maximum workers allowed. If none: cpu_count() or 1) * 5 :type max_workers: typing.Optional[int] """ if max_workers is None: # Use 3.5+ behavior diff --git a/tox.ini b/tox.ini index 9d7a57a..6342f2e 100644 --- a/tox.ini +++ b/tox.ini @@ -42,9 +42,9 @@ commands = flake8 [testenv:pep257] deps = - pep257 + pydocstyle usedevelop = False -commands = pep257 threaded +commands = pydocstyle threaded [testenv:install] deps = @@ -76,6 +76,9 @@ show-source = True count = True max-line-length = 120 +[pydocstyle] +ignore = D401, D203, D213 + [testenv:docs] usedevelop = False deps =