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
-----------------------
++++++++++++++++++
* 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)
++++++++++++++++++
# -*- 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:
""" # 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()
"""
def __init__(self, func):
- self.__doc__ = getattr(func, '__doc__')
+ self.__doc__ = getattr(func, "__doc__")
self.func = func
self.lock = threading.RLock()
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))
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
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
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")
# 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
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",
],
)
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):
"""
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)
return Check
-
class TestCachedProperty(unittest.TestCase):
"""Tests for cached_property"""
"""
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)
# 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):
@unittest_run_loop
async def test_none_cached_property(self):
+
class Check(object):
def __init__(self):
await self.assert_cached(Check(), None)
-
+
except ImportError:
pass # Running older version of Python that doesn't support asyncio
-
# 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)
self.assert_cached(check, 2)
def test_none_cached_property(self):
+
class Check(object):
def __init__(self):
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):
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
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
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
"""
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)
# 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
@unittest_run_loop
@asyncio.coroutine
def test_none_cached_property(self):
+
class Check(object):
def __init__(self):