From b3d5c7ff510c7a09cc717108008af6a43f0228ab Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Sun, 8 Apr 2018 17:19:00 -0500 Subject: [PATCH] Improved code formatting and prep for release 1.4.1 --- CONTRIBUTING.rst | 12 ++++-- HISTORY.rst | 3 ++ cached_property.py | 23 +++++++---- conftest.py | 14 +++---- requirements.txt | 2 + setup.py | 51 +++++++++++++------------ tests/test_async_cached_property.py | 16 ++++---- tests/test_cached_property.py | 19 +++++---- tests/test_coroutine_cached_property.py | 8 ++-- 9 files changed, 82 insertions(+), 66 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index ba7f9b6..1b16d5d 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -74,21 +74,25 @@ Ready to contribute? Here's how to set up `cached-property` for local developmen Now you can make your changes locally. -5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: + +5. Clean up the formatting:: + + $ black . + +6. When you're done making changes, check that your changes pass the tests, including testing other Python versions with tox:: - $ flake8 cached-property tests $ python setup.py test $ tox To get flake8 and tox, just pip install them into your virtualenv. -6. Commit your changes and push your branch to GitHub:: +7. Commit your changes and push your branch to GitHub:: $ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature -7. Submit a pull request through the GitHub website. +8. Submit a pull request through the GitHub website. Pull Request Guidelines ----------------------- diff --git a/HISTORY.rst b/HISTORY.rst index ac4fc15..7662de1 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,9 @@ History ++++++++++++++++++ * Added conftest.py to manifest so tests work properly off the tarball, thanks to @dotlambda +* Ensured new asyncio tests didn't break Python 2.7 builds on Debian, thanks to @pydanny +* Code formatting via black, thanks to @pydanny and @ambv + 1.4.0 (2018-02-25) ++++++++++++++++++ diff --git a/cached_property.py b/cached_property.py index 53edd60..77e33b8 100644 --- a/cached_property.py +++ b/cached_property.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- -__author__ = 'Daniel Greenfeld' -__email__ = 'pydanny@gmail.com' -__version__ = '1.4.0' -__license__ = 'BSD' +__author__ = "Daniel Greenfeld" +__email__ = "pydanny@gmail.com" +__version__ = "1.4.1" +__license__ = "BSD" from time import time import threading + try: import asyncio except ImportError: @@ -21,23 +22,27 @@ class cached_property(object): """ # noqa def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') + self.__doc__ = getattr(func, "__doc__") self.func = func def __get__(self, obj, cls): if obj is None: return self + if asyncio and asyncio.iscoroutinefunction(self.func): return self._wrap_in_coroutine(obj) + value = obj.__dict__[self.func.__name__] = self.func(obj) return value def _wrap_in_coroutine(self, obj): + @asyncio.coroutine def wrapper(): future = asyncio.ensure_future(self.func(obj)) obj.__dict__[self.func.__name__] = future return future + return wrapper() @@ -48,7 +53,7 @@ class threaded_cached_property(object): """ def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') + self.__doc__ = getattr(func, "__doc__") self.func = func self.lock = threading.RLock() @@ -62,6 +67,7 @@ class threaded_cached_property(object): try: # check if the value was computed before the lock was acquired return obj_dict[name] + except KeyError: # if not, do the calculation and release the lock return obj_dict.setdefault(name, self.func(obj)) @@ -120,6 +126,7 @@ class cached_property_with_ttl(object): self.__name__ = func.__name__ self.__module__ = func.__module__ + # Aliases to make cached_property_with_ttl easier to use cached_property_ttl = cached_property_with_ttl timed_cached_property = cached_property_with_ttl @@ -137,8 +144,8 @@ class threaded_cached_property_with_ttl(cached_property_with_ttl): def __get__(self, obj, cls): with self.lock: - return super(threaded_cached_property_with_ttl, self).__get__(obj, - cls) + return super(threaded_cached_property_with_ttl, self).__get__(obj, cls) + # Alias to make threaded_cached_property_with_ttl easier to use threaded_cached_property_ttl = threaded_cached_property_with_ttl diff --git a/conftest.py b/conftest.py index d68017d..37daf27 100644 --- a/conftest.py +++ b/conftest.py @@ -2,23 +2,19 @@ import sys # Whether "import asyncio" works -has_asyncio = ( - sys.version_info[0] == 3 and sys.version_info[1] >= 4 -) +has_asyncio = (sys.version_info[0] == 3 and sys.version_info[1] >= 4) # Whether the async and await keywords work -has_async_await = ( - sys.version_info[0] == 3 and sys.version_info[1] >= 5 -) +has_async_await = (sys.version_info[0] == 3 and sys.version_info[1] >= 5) -print('conftest.py', has_asyncio, has_async_await) +print("conftest.py", has_asyncio, has_async_await) collect_ignore = [] if not has_asyncio: - collect_ignore.append('tests/test_coroutine_cached_property.py') + collect_ignore.append("tests/test_coroutine_cached_property.py") if not has_async_await: - collect_ignore.append('tests/test_async_cached_property.py') + collect_ignore.append("tests/test_async_cached_property.py") diff --git a/requirements.txt b/requirements.txt index 19a2c2e..39a3a9c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,8 @@ # Testing and deployment packages. +black==18.4a0 coverage==4.4.2 pytest==3.5.0 pytest-cov==2.5.1 freezegun==0.3.10 +twine==1.11.0 wheel==0.30.0 diff --git a/setup.py b/setup.py index a94df4f..0b92575 100755 --- a/setup.py +++ b/setup.py @@ -10,46 +10,49 @@ try: except ImportError: from distutils.core import setup -__version__ = '1.4.0' +__version__ = "1.4.1" def read(fname): return codecs.open( - os.path.join(os.path.dirname(__file__), fname), 'r', 'utf-8').read() + os.path.join(os.path.dirname(__file__), fname), "r", "utf-8" + ).read() -readme = read('README.rst') -history = read('HISTORY.rst').replace('.. :changelog:', '') -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel upload') +readme = read("README.rst") +history = read("HISTORY.rst").replace(".. :changelog:", "") + +if sys.argv[-1] == "publish": + os.system("python setup.py sdist bdist_wheel") + os.system("twine upload dist/*") os.system("git tag -a %s -m 'version %s'" % (__version__, __version__)) os.system("git push --tags") sys.exit() setup( - name='cached-property', + name="cached-property", version=__version__, - description='A decorator for caching properties in classes.', - long_description=readme + '\n\n' + history, - author='Daniel Greenfeld', - author_email='pydanny@gmail.com', - url='https://github.com/pydanny/cached-property', - py_modules=['cached_property'], + description="A decorator for caching properties in classes.", + long_description=readme + "\n\n" + history, + author="Daniel Greenfeld", + author_email="pydanny@gmail.com", + url="https://github.com/pydanny/cached-property", + py_modules=["cached_property"], include_package_data=True, license="BSD", zip_safe=False, - keywords='cached-property', + keywords="cached-property", classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Natural Language :: English', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", "Programming Language :: Python :: 2", - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", ], ) diff --git a/tests/test_async_cached_property.py b/tests/test_async_cached_property.py index 6a9fb87..ee428e0 100644 --- a/tests/test_async_cached_property.py +++ b/tests/test_async_cached_property.py @@ -9,15 +9,15 @@ try: from freezegun import freeze_time import cached_property - def unittest_run_loop(f): + def wrapper(*args, **kwargs): coro = asyncio.coroutine(f) future = coro(*args, **kwargs) loop = asyncio.get_event_loop() loop.run_until_complete(future) - return wrapper + return wrapper def CheckFactory(cached_property_decorator, threadsafe=False): """ @@ -51,10 +51,12 @@ try: def run_threads(self, num_threads): threads = [] for _ in range(num_threads): + def call_add_cached(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(self.add_cached) + thread = Thread(target=call_add_cached) thread.start() threads.append(thread) @@ -63,7 +65,6 @@ try: return Check - class TestCachedProperty(unittest.TestCase): """Tests for cached_property""" @@ -80,7 +81,7 @@ try: """ Assert that both `add_cached` and 'cached_total` equal `expected` """ - print('assert_cached', check.add_cached) + print("assert_cached", check.add_cached) self.assertEqual(await check.add_cached, expected) self.assertEqual(check.cached_total, expected) @@ -103,8 +104,7 @@ try: # Typically descriptors return themselves if accessed though the class # rather than through an instance. - self.assertTrue(isinstance(Check.add_cached, - self.cached_property_factory)) + self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory)) @unittest_run_loop async def test_reset_cached_property(self): @@ -124,6 +124,7 @@ try: @unittest_run_loop async def test_none_cached_property(self): + class Check(object): def __init__(self): @@ -135,7 +136,6 @@ try: await self.assert_cached(Check(), None) - + except ImportError: pass # Running older version of Python that doesn't support asyncio - diff --git a/tests/test_cached_property.py b/tests/test_cached_property.py index 1e0e68a..5d8ea92 100644 --- a/tests/test_cached_property.py +++ b/tests/test_cached_property.py @@ -87,8 +87,7 @@ class TestCachedProperty(unittest.TestCase): # Typically descriptors return themselves if accessed though the class # rather than through an instance. - self.assertTrue(isinstance(Check.add_cached, - self.cached_property_factory)) + self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory)) def test_reset_cached_property(self): Check = CheckFactory(self.cached_property_factory) @@ -106,6 +105,7 @@ class TestCachedProperty(unittest.TestCase): self.assert_cached(check, 2) def test_none_cached_property(self): + class Check(object): def __init__(self): @@ -120,8 +120,8 @@ class TestCachedProperty(unittest.TestCase): def test_set_cached_property(self): Check = CheckFactory(self.cached_property_factory) check = Check() - check.add_cached = 'foo' - self.assertEqual(check.add_cached, 'foo') + check.add_cached = "foo" + self.assertEqual(check.add_cached, "foo") self.assertEqual(check.cached_total, 0) def test_threads(self): @@ -192,8 +192,7 @@ class TestCachedPropertyWithTTL(TestCachedProperty): self.assert_cached(check, 2) def test_threads_ttl_expiry(self): - Check = CheckFactory(self.cached_property_factory(ttl=100000), - threadsafe=True) + Check = CheckFactory(self.cached_property_factory(ttl=100000), threadsafe=True) check = Check() num_threads = 5 @@ -213,15 +212,15 @@ class TestCachedPropertyWithTTL(TestCachedProperty): self.assert_cached(check, 2 * num_threads) -class TestThreadedCachedPropertyWithTTL(TestThreadedCachedProperty, - TestCachedPropertyWithTTL): +class TestThreadedCachedPropertyWithTTL( + TestThreadedCachedProperty, TestCachedPropertyWithTTL +): """Tests for threaded_cached_property_with_ttl""" cached_property_factory = cached_property.threaded_cached_property_with_ttl def test_threads_ttl_expiry(self): - Check = CheckFactory(self.cached_property_factory(ttl=100000), - threadsafe=True) + Check = CheckFactory(self.cached_property_factory(ttl=100000), threadsafe=True) check = Check() num_threads = 5 diff --git a/tests/test_coroutine_cached_property.py b/tests/test_coroutine_cached_property.py index ede9baf..30723cf 100644 --- a/tests/test_coroutine_cached_property.py +++ b/tests/test_coroutine_cached_property.py @@ -13,11 +13,13 @@ import cached_property def unittest_run_loop(f): + def wrapper(*args, **kwargs): coro = asyncio.coroutine(f) future = coro(*args, **kwargs) loop = asyncio.get_event_loop() loop.run_until_complete(future) + return wrapper @@ -66,7 +68,7 @@ class TestCachedProperty(unittest.TestCase): """ Assert that both `add_cached` and 'cached_total` equal `expected` """ - print('assert_cached', check.add_cached) + print("assert_cached", check.add_cached) value = yield from check.add_cached self.assertEqual(value, expected) self.assertEqual(check.cached_total, expected) @@ -91,8 +93,7 @@ class TestCachedProperty(unittest.TestCase): # Typically descriptors return themselves if accessed though the class # rather than through an instance. - self.assertTrue(isinstance(Check.add_cached, - self.cached_property_factory)) + self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory)) @unittest_run_loop @asyncio.coroutine @@ -114,6 +115,7 @@ class TestCachedProperty(unittest.TestCase): @unittest_run_loop @asyncio.coroutine def test_none_cached_property(self): + class Check(object): def __init__(self): -- 2.30.2