Hello community, here is the log from the commit of package python-cached-property for openSUSE:Factory checked in at 2019-03-01 16:49:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-cached-property (Old) and /work/SRC/openSUSE:Factory/.python-cached-property.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cached-property" Fri Mar 1 16:49:04 2019 rev:6 rq:680387 version:1.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-cached-property/python-cached-property.changes 2019-02-01 12:03:43.503426927 +0100 +++ /work/SRC/openSUSE:Factory/.python-cached-property.new.28833/python-cached-property.changes 2019-03-01 16:49:05.241761430 +0100 @@ -1,0 +2,21 @@ +Mon Feb 25 08:43:46 UTC 2019 - John Vandenberg <jay...@gmail.com> + +- Add HISTORY.rst to %doc +- Update to v1.5.1 + * Added formal support for Python 3.7 + * Removed formal support for Python 3.3 +- from 1.4.3 + * Catch SyntaxError from asyncio import on older versions of Python +- from 1.4.2 + * Really fixed tests +- from 1.4.1 + * Added conftest.py to manifest so tests work properly off the tarball + * Ensured new asyncio tests didn't break Python 2.7 builds on Debian + * Code formatting via black +- from 1.4.0 + * Added asyncio support + * Remove Python 2.6 support, whose end of life was 5 years ago +- from 1.3.1 + * Validate for Python 3.6 + +------------------------------------------------------------------- Old: ---- cached-property-1.3.0.tar.gz New: ---- cached-property-1.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-cached-property.spec ++++++ --- /var/tmp/diff_new_pack.flOcxu/_old 2019-03-01 16:49:06.521760948 +0100 +++ /var/tmp/diff_new_pack.flOcxu/_new 2019-03-01 16:49:06.525760946 +0100 @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-cached-property -Version: 1.3.0 +Version: 1.5.1 Release: 0 Summary: A decorator for caching properties in classes License: BSD-3-Clause @@ -29,6 +29,7 @@ # https://github.com/pydanny/cached-property/pull/125 Patch0: freezegun-skip.patch BuildRequires: %{python_module freezegun} +BuildRequires: %{python_module nose} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -36,7 +37,7 @@ %python_subpackages %description -A decorator for caching properties in classes.It makes caching of time or +A decorator for caching properties in classes. It makes caching of time or computational expensive properties quick and easy and it works in Python 2 and 3. @@ -52,11 +53,16 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -%python_expand $python -m unittest discover -v +python2 -m nose -e 'test_(async|coroutine)_cached_property' +%if %python_version_nodots < 35 +python3 -m nose -e 'test_(async|coroutine)_cached_property' +%else +python3 -m nose +%endif %files %{python_files} %license LICENSE -%doc AUTHORS.rst README.rst +%doc AUTHORS.rst README.rst HISTORY.rst %{python_sitelib}/* %changelog ++++++ cached-property-1.3.0.tar.gz -> cached-property-1.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/AUTHORS.rst new/cached-property-1.5.1/AUTHORS.rst --- old/cached-property-1.3.0/AUTHORS.rst 2015-11-25 02:43:07.000000000 +0100 +++ new/cached-property-1.5.1/AUTHORS.rst 2018-09-05 17:18:25.000000000 +0200 @@ -5,7 +5,7 @@ Development Lead ---------------- -* Daniel Roy Greenfeld <pyda...@gmail.com> +* Daniel Roy Greenfeld (@pydanny) * Audrey Roy Greenfeld (@audreyr) Contributors @@ -17,3 +17,4 @@ * Adam Williamson <awilliam AT redhat DOT com> * Ionel Cristian Mărieș (@ionelmc) * Malyshev Artem (@proofit404) +* Volker Braun (@vbraun) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/CONTRIBUTING.rst new/cached-property-1.5.1/CONTRIBUTING.rst --- old/cached-property-1.3.0/CONTRIBUTING.rst 2015-04-28 18:31:36.000000000 +0200 +++ new/cached-property-1.5.1/CONTRIBUTING.rst 2018-09-05 17:18:25.000000000 +0200 @@ -74,21 +74,26 @@ 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 (must be running at least Python 3.6):: + + $ pip install -U black + $ 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 + $ pytest tests/ $ tox - To get flake8 and tox, just pip install them into your virtualenv. + To get tox, just pip install it 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 ----------------------- @@ -99,7 +104,7 @@ 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst. -3. The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. Check +3. The pull request should work for Python 2.7, and 3.3, 3.4, 3.5, 3.6 and for PyPy. Check https://travis-ci.org/pydanny/cached-property/pull_requests and make sure that the tests pass for all supported Python versions. @@ -108,4 +113,5 @@ To run a subset of tests:: - $ python -m unittest tests.test_cached-property \ No newline at end of file + $ python -m unittest tests.test_cached-property + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/HISTORY.rst new/cached-property-1.5.1/HISTORY.rst --- old/cached-property-1.3.0/HISTORY.rst 2015-11-25 02:43:07.000000000 +0100 +++ new/cached-property-1.5.1/HISTORY.rst 2018-09-05 17:29:20.000000000 +0200 @@ -3,9 +3,47 @@ History ------- +1.5.1 (2018-08-05) +++++++++++++++++++ + +* Added formal support for Python 3.7 +* Removed formal support for Python 3.3 + +1.4.3 (2018-06-14) ++++++++++++++++++++ + +* Catch SyntaxError from asyncio import on older versions of Python, thanks to @asottile + +1.4.2 (2018-04-08) +++++++++++++++++++ + +* Really fixed tests, thanks to @pydanny + +1.4.1 (2018-04-08) +++++++++++++++++++ + +* 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) +++++++++++++++++++ + +* Added asyncio support, thanks to @vbraun +* Remove Python 2.6 support, whose end of life was 5 years ago, thanks to @pydanny + + +1.3.1 (2017-09-21) +++++++++++++++++++ + +* Validate for Python 3.6 + + 1.3.0 (2015-11-24) ++++++++++++++++++ +* Drop some non-ASCII characters from HISTORY.rst, thanks to @AdamWill * Added official support for Python 3.5, thanks to @pydanny and @audreyr * Removed confusingly placed lock from example, thanks to @ionelmc * Corrected invalidation cache documentation, thanks to @proofit404 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/MANIFEST.in new/cached-property-1.5.1/MANIFEST.in --- old/cached-property-1.3.0/MANIFEST.in 2015-04-28 18:31:36.000000000 +0200 +++ new/cached-property-1.5.1/MANIFEST.in 2018-09-05 17:18:25.000000000 +0200 @@ -8,4 +8,4 @@ recursive-exclude * __pycache__ recursive-exclude * *.py[co] -recursive-include docs *.rst conf.py Makefile make.bat \ No newline at end of file +recursive-include docs *.rst conftest.py Makefile make.bat diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/PKG-INFO new/cached-property-1.5.1/PKG-INFO --- old/cached-property-1.3.0/PKG-INFO 2015-11-25 02:50:10.000000000 +0100 +++ new/cached-property-1.5.1/PKG-INFO 2018-09-05 17:29:56.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cached-property -Version: 1.3.0 +Version: 1.5.1 Summary: A decorator for caching properties in classes. Home-page: https://github.com/pydanny/cached-property Author: Daniel Greenfeld @@ -14,7 +14,11 @@ :target: https://pypi.python.org/pypi/cached-property .. image:: https://img.shields.io/travis/pydanny/cached-property/master.svg - :target: https://travis-ci.org/pydanny/cached-property + :target: https://travis-ci.org/pydanny/cached-property + + .. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + :alt: Code style: black A decorator for caching properties in classes. @@ -153,6 +157,49 @@ >>> self.assertEqual(m.boardwalk, 550) + Working with async/await (Python 3.5+) + -------------------------------------- + + The cached property can be async, in which case you have to use await + as usual to get the value. Because of the caching, the value is only + computed once and then cached: + + .. code-block:: python + + from cached_property import cached_property + + class Monopoly(object): + + def __init__(self): + self.boardwalk_price = 500 + + @cached_property + async def boardwalk(self): + self.boardwalk_price += 50 + return self.boardwalk_price + + Now use it: + + .. code-block:: python + + >>> async def print_boardwalk(): + ... monopoly = Monopoly() + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + >>> import asyncio + >>> asyncio.get_event_loop().run_until_complete(print_boardwalk()) + 550 + 550 + 550 + + Note that this does not work with threading either, most asyncio + objects are not thread-safe. And if you run separate event loops in + each thread, the cached version will most likely have the wrong event + loop. To summarize, either use cooperative multitasking (event loop) + or threading, but not both at the same time. + + Timing out the cache -------------------- @@ -193,7 +240,7 @@ Credits -------- - * Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package uses an implementation that matches the Bottle version. + * Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package originally used an implementation that matched the Bottle version. * Reinout Van Rees for pointing out the `cached_property` decorator to me. * My awesome wife `@audreyr`_ who created `cookiecutter`_, which meant rolling this out took me just 15 minutes. * @tinche for pointing out the threading issue and providing a solution. @@ -202,15 +249,64 @@ .. _`@audreyr`: https://github.com/audreyr .. _`cookiecutter`: https://github.com/audreyr/cookiecutter + Support This Project + --------------------------- + + This project is maintained by volunteers. Support their efforts by spreading the word about: + + .. image:: https://cdn.shopify.com/s/files/1/0304/6901/t/2/assets/logo.png?8399580890922549623 + :name: Two Scoops Press + :align: center + :alt: Two Scoops Press + :target: https://www.twoscoopspress.com + History ------- + 1.5.1 (2018-08-05) + ++++++++++++++++++ + + * Added formal support for Python 3.7 + * Removed formal support for Python 3.3 + + 1.4.3 (2018-06-14) + +++++++++++++++++++ + + * Catch SyntaxError from asyncio import on older versions of Python, thanks to @asottile + + 1.4.2 (2018-04-08) + ++++++++++++++++++ + + * Really fixed tests, thanks to @pydanny + + 1.4.1 (2018-04-08) + ++++++++++++++++++ + + * 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) + ++++++++++++++++++ + + * Added asyncio support, thanks to @vbraun + * Remove Python 2.6 support, whose end of life was 5 years ago, thanks to @pydanny + + + 1.3.1 (2017-09-21) + ++++++++++++++++++ + + * Validate for Python 3.6 + + 1.3.0 (2015-11-24) ++++++++++++++++++ + * Drop some non-ASCII characters from HISTORY.rst, thanks to @AdamWill * Added official support for Python 3.5, thanks to @pydanny and @audreyr * Removed confusingly placed lock from example, thanks to @ionelmc * Corrected invalidation cache documentation, thanks to @proofit404 @@ -276,9 +372,9 @@ Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/README.rst new/cached-property-1.5.1/README.rst --- old/cached-property-1.3.0/README.rst 2015-11-25 02:48:12.000000000 +0100 +++ new/cached-property-1.5.1/README.rst 2018-09-05 17:28:54.000000000 +0200 @@ -6,7 +6,11 @@ :target: https://pypi.python.org/pypi/cached-property .. image:: https://img.shields.io/travis/pydanny/cached-property/master.svg - :target: https://travis-ci.org/pydanny/cached-property + :target: https://travis-ci.org/pydanny/cached-property + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + :alt: Code style: black A decorator for caching properties in classes. @@ -145,6 +149,49 @@ >>> self.assertEqual(m.boardwalk, 550) +Working with async/await (Python 3.5+) +-------------------------------------- + +The cached property can be async, in which case you have to use await +as usual to get the value. Because of the caching, the value is only +computed once and then cached: + +.. code-block:: python + + from cached_property import cached_property + + class Monopoly(object): + + def __init__(self): + self.boardwalk_price = 500 + + @cached_property + async def boardwalk(self): + self.boardwalk_price += 50 + return self.boardwalk_price + +Now use it: + +.. code-block:: python + + >>> async def print_boardwalk(): + ... monopoly = Monopoly() + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + >>> import asyncio + >>> asyncio.get_event_loop().run_until_complete(print_boardwalk()) + 550 + 550 + 550 + +Note that this does not work with threading either, most asyncio +objects are not thread-safe. And if you run separate event loops in +each thread, the cached version will most likely have the wrong event +loop. To summarize, either use cooperative multitasking (event loop) +or threading, but not both at the same time. + + Timing out the cache -------------------- @@ -185,7 +232,7 @@ Credits -------- -* Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package uses an implementation that matches the Bottle version. +* Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package originally used an implementation that matched the Bottle version. * Reinout Van Rees for pointing out the `cached_property` decorator to me. * My awesome wife `@audreyr`_ who created `cookiecutter`_, which meant rolling this out took me just 15 minutes. * @tinche for pointing out the threading issue and providing a solution. @@ -193,3 +240,14 @@ .. _`@audreyr`: https://github.com/audreyr .. _`cookiecutter`: https://github.com/audreyr/cookiecutter + +Support This Project +--------------------------- + +This project is maintained by volunteers. Support their efforts by spreading the word about: + +.. image:: https://cdn.shopify.com/s/files/1/0304/6901/t/2/assets/logo.png?8399580890922549623 + :name: Two Scoops Press + :align: center + :alt: Two Scoops Press + :target: https://www.twoscoopspress.com diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/cached_property.egg-info/PKG-INFO new/cached-property-1.5.1/cached_property.egg-info/PKG-INFO --- old/cached-property-1.3.0/cached_property.egg-info/PKG-INFO 2015-11-25 02:50:10.000000000 +0100 +++ new/cached-property-1.5.1/cached_property.egg-info/PKG-INFO 2018-09-05 17:29:56.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cached-property -Version: 1.3.0 +Version: 1.5.1 Summary: A decorator for caching properties in classes. Home-page: https://github.com/pydanny/cached-property Author: Daniel Greenfeld @@ -14,7 +14,11 @@ :target: https://pypi.python.org/pypi/cached-property .. image:: https://img.shields.io/travis/pydanny/cached-property/master.svg - :target: https://travis-ci.org/pydanny/cached-property + :target: https://travis-ci.org/pydanny/cached-property + + .. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/ambv/black + :alt: Code style: black A decorator for caching properties in classes. @@ -153,6 +157,49 @@ >>> self.assertEqual(m.boardwalk, 550) + Working with async/await (Python 3.5+) + -------------------------------------- + + The cached property can be async, in which case you have to use await + as usual to get the value. Because of the caching, the value is only + computed once and then cached: + + .. code-block:: python + + from cached_property import cached_property + + class Monopoly(object): + + def __init__(self): + self.boardwalk_price = 500 + + @cached_property + async def boardwalk(self): + self.boardwalk_price += 50 + return self.boardwalk_price + + Now use it: + + .. code-block:: python + + >>> async def print_boardwalk(): + ... monopoly = Monopoly() + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + ... print(await monopoly.boardwalk) + >>> import asyncio + >>> asyncio.get_event_loop().run_until_complete(print_boardwalk()) + 550 + 550 + 550 + + Note that this does not work with threading either, most asyncio + objects are not thread-safe. And if you run separate event loops in + each thread, the cached version will most likely have the wrong event + loop. To summarize, either use cooperative multitasking (event loop) + or threading, but not both at the same time. + + Timing out the cache -------------------- @@ -193,7 +240,7 @@ Credits -------- - * Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package uses an implementation that matches the Bottle version. + * Pip, Django, Werkzueg, Bottle, Pyramid, and Zope for having their own implementations. This package originally used an implementation that matched the Bottle version. * Reinout Van Rees for pointing out the `cached_property` decorator to me. * My awesome wife `@audreyr`_ who created `cookiecutter`_, which meant rolling this out took me just 15 minutes. * @tinche for pointing out the threading issue and providing a solution. @@ -202,15 +249,64 @@ .. _`@audreyr`: https://github.com/audreyr .. _`cookiecutter`: https://github.com/audreyr/cookiecutter + Support This Project + --------------------------- + + This project is maintained by volunteers. Support their efforts by spreading the word about: + + .. image:: https://cdn.shopify.com/s/files/1/0304/6901/t/2/assets/logo.png?8399580890922549623 + :name: Two Scoops Press + :align: center + :alt: Two Scoops Press + :target: https://www.twoscoopspress.com + History ------- + 1.5.1 (2018-08-05) + ++++++++++++++++++ + + * Added formal support for Python 3.7 + * Removed formal support for Python 3.3 + + 1.4.3 (2018-06-14) + +++++++++++++++++++ + + * Catch SyntaxError from asyncio import on older versions of Python, thanks to @asottile + + 1.4.2 (2018-04-08) + ++++++++++++++++++ + + * Really fixed tests, thanks to @pydanny + + 1.4.1 (2018-04-08) + ++++++++++++++++++ + + * 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) + ++++++++++++++++++ + + * Added asyncio support, thanks to @vbraun + * Remove Python 2.6 support, whose end of life was 5 years ago, thanks to @pydanny + + + 1.3.1 (2017-09-21) + ++++++++++++++++++ + + * Validate for Python 3.6 + + 1.3.0 (2015-11-24) ++++++++++++++++++ + * Drop some non-ASCII characters from HISTORY.rst, thanks to @AdamWill * Added official support for Python 3.5, thanks to @pydanny and @audreyr * Removed confusingly placed lock from example, thanks to @ionelmc * Corrected invalidation cache documentation, thanks to @proofit404 @@ -276,9 +372,9 @@ Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/cached_property.egg-info/SOURCES.txt new/cached-property-1.5.1/cached_property.egg-info/SOURCES.txt --- old/cached-property-1.3.0/cached_property.egg-info/SOURCES.txt 2015-11-25 02:50:10.000000000 +0100 +++ new/cached-property-1.5.1/cached_property.egg-info/SOURCES.txt 2018-09-05 17:29:56.000000000 +0200 @@ -13,4 +13,6 @@ cached_property.egg-info/not-zip-safe cached_property.egg-info/top_level.txt tests/__init__.py -tests/test_cached_property.py \ No newline at end of file +tests/test_async_cached_property.py +tests/test_cached_property.py +tests/test_coroutine_cached_property.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/cached_property.py new/cached-property-1.5.1/cached_property.py --- old/cached-property-1.3.0/cached_property.py 2015-11-25 02:48:12.000000000 +0100 +++ new/cached-property-1.5.1/cached_property.py 2018-09-05 17:29:47.000000000 +0200 @@ -1,13 +1,18 @@ # -*- coding: utf-8 -*- -__author__ = 'Daniel Greenfeld' -__email__ = 'pyda...@gmail.com' -__version__ = '1.3.0' -__license__ = 'BSD' +__author__ = "Daniel Greenfeld" +__email__ = "pyda...@gmail.com" +__version__ = "1.5.1" +__license__ = "BSD" from time import time import threading +try: + import asyncio +except (ImportError, SyntaxError): + asyncio = None + class cached_property(object): """ @@ -17,15 +22,29 @@ """ # 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() + class threaded_cached_property(object): """ @@ -34,7 +53,7 @@ """ def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') + self.__doc__ = getattr(func, "__doc__") self.func = func self.lock = threading.RLock() @@ -48,6 +67,7 @@ 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)) @@ -106,6 +126,7 @@ 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 @@ -123,8 +144,8 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/setup.cfg new/cached-property-1.5.1/setup.cfg --- old/cached-property-1.3.0/setup.cfg 2015-11-25 02:50:10.000000000 +0100 +++ new/cached-property-1.5.1/setup.cfg 2018-09-05 17:29:56.000000000 +0200 @@ -4,5 +4,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/setup.py new/cached-property-1.5.1/setup.py --- old/cached-property-1.3.0/setup.py 2015-11-25 02:48:12.000000000 +0100 +++ new/cached-property-1.5.1/setup.py 2018-09-05 17:29:42.000000000 +0200 @@ -3,47 +3,56 @@ import os import sys +import codecs try: from setuptools import setup except ImportError: from distutils.core import setup -__version__ = '1.3.0' +__version__ = "1.5.1" -readme = open('README.rst').read() -history = open('HISTORY.rst').read().replace('.. :changelog:', '') -if sys.argv[-1] == 'publish': - os.system('python setup.py sdist bdist_wheel upload') +def read(fname): + return codecs.open( + 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") + 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='pyda...@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="pyda...@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.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 :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7" ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/tests/test_async_cached_property.py new/cached-property-1.5.1/tests/test_async_cached_property.py --- old/cached-property-1.3.0/tests/test_async_cached_property.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cached-property-1.5.1/tests/test_async_cached_property.py 2018-09-05 17:18:25.000000000 +0200 @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- +import asyncio +import time +import unittest +from threading import Lock, Thread +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 + +def CheckFactory(cached_property_decorator, threadsafe=False): + """ + Create dynamically a Check class whose add_cached method is decorated by + the cached_property_decorator. + """ + + class Check(object): + + def __init__(self): + self.control_total = 0 + self.cached_total = 0 + self.lock = Lock() + + async def add_control(self): + self.control_total += 1 + return self.control_total + + @cached_property_decorator + async def add_cached(self): + if threadsafe: + time.sleep(1) + # Need to guard this since += isn't atomic. + with self.lock: + self.cached_total += 1 + else: + self.cached_total += 1 + + return self.cached_total + + 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) + for thread in threads: + thread.join() + + return Check + +class TestCachedProperty(unittest.TestCase): + """Tests for cached_property""" + + cached_property_factory = cached_property.cached_property + + async def assert_control(self, check, expected): + """ + Assert that both `add_control` and 'control_total` equal `expected` + """ + self.assertEqual(await check.add_control(), expected) + self.assertEqual(check.control_total, expected) + + async def assert_cached(self, check, expected): + """ + Assert that both `add_cached` and 'cached_total` equal `expected` + """ + print("assert_cached", check.add_cached) + self.assertEqual(await check.add_cached, expected) + self.assertEqual(check.cached_total, expected) + + @unittest_run_loop + async def test_cached_property(self): + Check = CheckFactory(self.cached_property_factory) + check = Check() + + # The control shows that we can continue to add 1 + await self.assert_control(check, 1) + await self.assert_control(check, 2) + + # The cached version demonstrates how nothing is added after the first + await self.assert_cached(check, 1) + await self.assert_cached(check, 1) + + # The cache does not expire + with freeze_time("9999-01-01"): + await self.assert_cached(check, 1) + + # Typically descriptors return themselves if accessed though the class + # rather than through an instance. + self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory)) + + @unittest_run_loop + async def test_reset_cached_property(self): + Check = CheckFactory(self.cached_property_factory) + check = Check() + + # Run standard cache assertion + await self.assert_cached(check, 1) + await self.assert_cached(check, 1) + + # Clear the cache + del check.add_cached + + # Value is cached again after the next access + await self.assert_cached(check, 2) + await self.assert_cached(check, 2) + + @unittest_run_loop + async def test_none_cached_property(self): + + class Check(object): + + def __init__(self): + self.cached_total = None + + @self.cached_property_factory + async def add_cached(self): + return self.cached_total + + await self.assert_cached(Check(), None) \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/tests/test_cached_property.py new/cached-property-1.5.1/tests/test_cached_property.py --- old/cached-property-1.3.0/tests/test_cached_property.py 2015-04-28 18:31:36.000000000 +0200 +++ new/cached-property-1.5.1/tests/test_cached_property.py 2018-09-05 17:18:25.000000000 +0200 @@ -87,8 +87,7 @@ # 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 @@ self.assert_cached(check, 2) def test_none_cached_property(self): + class Check(object): def __init__(self): @@ -120,8 +120,8 @@ 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 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cached-property-1.3.0/tests/test_coroutine_cached_property.py new/cached-property-1.5.1/tests/test_coroutine_cached_property.py --- old/cached-property-1.3.0/tests/test_coroutine_cached_property.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cached-property-1.5.1/tests/test_coroutine_cached_property.py 2018-09-05 17:18:25.000000000 +0200 @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +""" +The same tests as in :mod:`.test_async_cached_property`, but with the old +yield from instead of the new async/await syntax. Used to test Python 3.4 +compatibility which has asyncio but doesn't have async/await yet. +""" + +import unittest +import asyncio +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 + + +def CheckFactory(cached_property_decorator): + """ + Create dynamically a Check class whose add_cached method is decorated by + the cached_property_decorator. + """ + + class Check(object): + + def __init__(self): + self.control_total = 0 + self.cached_total = 0 + + @asyncio.coroutine + def add_control(self): + self.control_total += 1 + return self.control_total + + @cached_property_decorator + @asyncio.coroutine + def add_cached(self): + self.cached_total += 1 + return self.cached_total + + return Check + + +class TestCachedProperty(unittest.TestCase): + """Tests for cached_property""" + + cached_property_factory = cached_property.cached_property + + @asyncio.coroutine + def assert_control(self, check, expected): + """ + Assert that both `add_control` and 'control_total` equal `expected` + """ + value = yield from check.add_control() + self.assertEqual(value, expected) + self.assertEqual(check.control_total, expected) + + @asyncio.coroutine + def assert_cached(self, check, expected): + """ + Assert that both `add_cached` and 'cached_total` equal `expected` + """ + print("assert_cached", check.add_cached) + value = yield from check.add_cached + self.assertEqual(value, expected) + self.assertEqual(check.cached_total, expected) + + @unittest_run_loop + @asyncio.coroutine + def test_cached_property(self): + Check = CheckFactory(self.cached_property_factory) + check = Check() + + # The control shows that we can continue to add 1 + yield from self.assert_control(check, 1) + yield from self.assert_control(check, 2) + + # The cached version demonstrates how nothing is added after the first + yield from self.assert_cached(check, 1) + yield from self.assert_cached(check, 1) + + # The cache does not expire + with freeze_time("9999-01-01"): + yield from self.assert_cached(check, 1) + + # Typically descriptors return themselves if accessed though the class + # rather than through an instance. + self.assertTrue(isinstance(Check.add_cached, self.cached_property_factory)) + + @unittest_run_loop + @asyncio.coroutine + def test_reset_cached_property(self): + Check = CheckFactory(self.cached_property_factory) + check = Check() + + # Run standard cache assertion + yield from self.assert_cached(check, 1) + yield from self.assert_cached(check, 1) + + # Clear the cache + del check.add_cached + + # Value is cached again after the next access + yield from self.assert_cached(check, 2) + yield from self.assert_cached(check, 2) + + @unittest_run_loop + @asyncio.coroutine + def test_none_cached_property(self): + + class Check(object): + + def __init__(self): + self.cached_total = None + + @self.cached_property_factory + @asyncio.coroutine + def add_cached(self): + return self.cached_total + + yield from self.assert_cached(Check(), None) ++++++ freezegun-skip.patch ++++++ --- /var/tmp/diff_new_pack.flOcxu/_old 2019-03-01 16:49:06.593760920 +0100 +++ /var/tmp/diff_new_pack.flOcxu/_new 2019-03-01 16:49:06.597760919 +0100 @@ -1,12 +1,12 @@ -Index: cached-property-1.3.0/tests/test_cached_property.py +Index: cached-property-1.5.1/tests/test_cached_property.py =================================================================== ---- cached-property-1.3.0.orig/tests/test_cached_property.py -+++ cached-property-1.3.0/tests/test_cached_property.py -@@ -191,6 +191,7 @@ class TestCachedPropertyWithTTL(TestCach +--- cached-property-1.5.1.orig/tests/test_cached_property.py ++++ cached-property-1.5.1/tests/test_cached_property.py +@@ -191,6 +191,7 @@ self.assert_cached(check, 2) self.assert_cached(check, 2) + @unittest.skip("new freezegun breaks behaviour of this test") 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()