From 91588e74f65a5ffb486654c1ae73c8c06471e27f Mon Sep 17 00:00:00 2001 From: cevans87 Date: Wed, 5 Jun 2019 12:20:39 -0700 Subject: [PATCH] Supports Py36 --- .travis.yml | 11 +++++++---- README.md | 2 +- atools/async_test_case_decorator.py | 3 +-- atools/decorator_mixin.py | 3 +-- setup.cfg | 2 ++ setup.py | 6 +++--- test/test_memoize_decorator.py | 23 +++++++++++++++-------- test/test_rate_decorator.py | 3 +-- 8 files changed, 31 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index b1a7c1f..28e1289 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,18 @@ language: python python: -- '3.7' + - '3.6' + - '3.7' dist: xenial env: PYTHONPATH=. before_install: - - pip install pytest pytest-cov - - pip install coveralls + - pip install pytest pytest-cov + - pip install coveralls +install: + - python setup.py -q install script: pytest --verbose --cov=atools after_success: - - coveralls + - coveralls deploy: provider: pypi user: cevans87 diff --git a/README.md b/README.md index a32181e..3751898 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![Build Status](https://travis-ci.org/cevans87/atools.svg?branch=master&kill_cache=1)](https://travis-ci.org/cevans87/atools) [![Coverage Status](https://coveralls.io/repos/github/cevans87/atools/badge.svg?branch=master&kill_cache=1)](https://coveralls.io/github/cevans87/atools?branch=master) # atools -Python 3.7+ async-enabled decorators and tools including +Python 3.6+ async-enabled decorators and tools including - __memoize__ - a function decorator for sync and async functions that memoizes results. - __async_test_case__ - a test class/function decorator that enables test functions to be async. diff --git a/atools/async_test_case_decorator.py b/atools/async_test_case_decorator.py index ce4a95b..7d90f08 100644 --- a/atools/async_test_case_decorator.py +++ b/atools/async_test_case_decorator.py @@ -1,4 +1,3 @@ -from __future__ import annotations import asyncio from atools.decorator_mixin import DecoratorMixin, Fn, Decoratee, Decorator import inspect @@ -44,7 +43,7 @@ def __init__(self, fn: Fn) -> None: def __call__(self, *args, **kwargs) -> Any: sync_result = self._fn(*args, **kwargs) if inspect.iscoroutinefunction(self._fn): - return asyncio.run(sync_result) + return asyncio.get_event_loop().run_until_complete(sync_result) elif not inspect.iscoroutine(sync_result): return sync_result else: diff --git a/atools/decorator_mixin.py b/atools/decorator_mixin.py index 0d3ae11..cfdf99f 100644 --- a/atools/decorator_mixin.py +++ b/atools/decorator_mixin.py @@ -1,4 +1,3 @@ -from __future__ import annotations from functools import wraps import inspect from typing import Any, Awaitable, Callable, Dict, Optional, Tuple, Type, Union @@ -13,7 +12,7 @@ class _DecoratorMeta(type): def __new__( mcs, name: str, bases: Tuple[Type, ...], namespace: Dict[str, Any] - ) -> _DecoratorMeta: + ) -> '_DecoratorMeta': # DecoratorMixin has a __doc__, but we want the __doc__ from the actual decorator class. if len(bases) > 1 and bases[0] is DecoratorMixin and '__doc__' not in namespace: namespace['__doc__'] = bases[1].__doc__ diff --git a/setup.cfg b/setup.cfg index 4fd6125..30614c3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,5 +6,7 @@ long_description_content_type = text/markdown [options] packages = atools +install_requires = + dataclasses>="0.6";python_version=="3.6" py_modules = __init__ diff --git a/setup.py b/setup.py index 0682cc6..3a2fd23 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,12 @@ setup( name='atools', - version='0.5.2', + version='0.6.0', packages=['', 'atools'], - python_requires='>=3.7', + python_requires='>=3.6', url='https://github.com/cevans87/atools', license='mit', author='cevans', author_email='c.d.evans87@gmail.com', - description='Python 3.7+ async decorators and testing tools' + description='Python 3.6+ async decorators and testing tools' ) diff --git a/test/test_memoize_decorator.py b/test/test_memoize_decorator.py index 7f44805..fce0d07 100644 --- a/test/test_memoize_decorator.py +++ b/test/test_memoize_decorator.py @@ -1,4 +1,6 @@ -from asyncio import coroutine, create_task, Event, gather, get_event_loop +from asyncio import ( + coroutine, ensure_future, Event, gather, get_event_loop, new_event_loop, set_event_loop +) from atools import async_test_case, memoize from datetime import timedelta import unittest @@ -7,7 +9,7 @@ @async_test_case class TestMemoize(unittest.TestCase): - + def test_zero_args(self) -> None: body = MagicMock() @@ -348,12 +350,17 @@ def foo() -> None: def test_async_no_event_loop_does_not_raise(self) -> None: # Show that we decorate without having an active event loop - with self.assertRaises(RuntimeError): - self.assertIsNone(get_event_loop()) + # noinspection PyTypeChecker + set_event_loop(None) + try: + with self.assertRaises(RuntimeError): + self.assertIsNone(get_event_loop()) - @memoize - async def foo() -> None: - ... + @memoize + async def foo() -> None: + ... + finally: + set_event_loop(new_event_loop()) def test_memoizes_class(self) -> None: body = MagicMock() @@ -449,7 +456,7 @@ async def foo() -> int: await foo_finish_event.wait() return 0 - task_a, task_b = create_task(foo()), create_task(foo()) + task_a, task_b = ensure_future(foo()), ensure_future(foo()) await foo_start_event.wait() foo_finish_event.set() diff --git a/test/test_rate_decorator.py b/test/test_rate_decorator.py index da1ccc5..c31f32c 100644 --- a/test/test_rate_decorator.py +++ b/test/test_rate_decorator.py @@ -1,4 +1,3 @@ -from __future__ import annotations import asyncio from asyncio import gather from atools import async_test_case, rate @@ -111,7 +110,7 @@ async def foo() -> None: await foo() - task = asyncio.create_task(foo()) + task = asyncio.ensure_future(foo()) while foo.rate.async_waiters != 1: await asyncio.sleep(0)