Hello community,
here is the log from the commit of package python-async_generator for
openSUSE:Factory checked in at 2019-03-05 12:19:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-async_generator (Old)
and /work/SRC/openSUSE:Factory/.python-async_generator.new.28833 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-async_generator"
Tue Mar 5 12:19:19 2019 rev:4 rq:680420 version:1.10
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-async_generator/python-async_generator.changes
2018-05-11 09:18:30.526007336 +0200
+++
/work/SRC/openSUSE:Factory/.python-async_generator.new.28833/python-async_generator.changes
2019-03-05 12:19:32.628947159 +0100
@@ -1,0 +2,8 @@
+Fri Mar 1 09:47:28 UTC 2019 - Ondřej Súkup <[email protected]>
+
+- update to 1.10
+- remove unnneded deps
+- fix licenses
+ * Add support for PEP 525-style garbage collection hooks
+
+-------------------------------------------------------------------
Old:
----
async_generator-1.9.tar.gz
New:
----
async_generator-1.10.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-async_generator.spec ++++++
--- /var/tmp/diff_new_pack.3IKhjT/_old 2019-03-05 12:19:33.064947026 +0100
+++ /var/tmp/diff_new_pack.3IKhjT/_new 2019-03-05 12:19:33.068947025 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-async_generator
#
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -12,30 +12,25 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-async_generator
-Version: 1.9
+Version: 1.10
Release: 0
Summary: Async generators and context managers for Python 3.5+
-License: MIT
+License: MIT OR Apache-2.0
Group: Development/Languages/Python
-Url: https://github.com/python-trio/async_generator
+URL: https://github.com/python-trio/async_generator
Source:
https://files.pythonhosted.org/packages/source/a/async_generator/async_generator-%{version}.tar.gz
-BuildRequires: %{python_module devel >= 3.5}
BuildRequires: %{python_module pytest}
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
-%ifpython3
-Requires: python3-base >= 3.5
-%endif
BuildArch: noarch
-
%python_subpackages
%description
@@ -53,10 +48,12 @@
%python_expand %fdupes %{buildroot}%{$python_sitelib}
%check
-%python_exec setup.py test
+%python_exec -m pytest
%files %{python_files}
%doc README.rst
+%license LICENSE.MIT
+%license LICENSE.APACHE2
%{python_sitelib}/*
%changelog
++++++ async_generator-1.9.tar.gz -> async_generator-1.10.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/CONTRIBUTING.md
new/async_generator-1.10/CONTRIBUTING.md
--- old/async_generator-1.9/CONTRIBUTING.md 1970-01-01 01:00:00.000000000
+0100
+++ new/async_generator-1.10/CONTRIBUTING.md 2018-01-19 13:51:28.000000000
+0100
@@ -0,0 +1,2 @@
+For the Trio contributing guide, see:
+ https://trio.readthedocs.io/en/latest/contributing.html
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/LICENSE
new/async_generator-1.10/LICENSE
--- old/async_generator-1.9/LICENSE 1970-01-01 01:00:00.000000000 +0100
+++ new/async_generator-1.10/LICENSE 2018-01-19 13:51:28.000000000 +0100
@@ -0,0 +1,3 @@
+This software is made available under the terms of *either* of the
+licenses found in LICENSE.APACHE2 or LICENSE.MIT. Contributions to
+trio are made under the terms of *both* these licenses.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/LICENSE.APACHE2
new/async_generator-1.10/LICENSE.APACHE2
--- old/async_generator-1.9/LICENSE.APACHE2 1970-01-01 01:00:00.000000000
+0100
+++ new/async_generator-1.10/LICENSE.APACHE2 2018-01-19 13:51:28.000000000
+0100
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/LICENSE.MIT
new/async_generator-1.10/LICENSE.MIT
--- old/async_generator-1.9/LICENSE.MIT 1970-01-01 01:00:00.000000000 +0100
+++ new/async_generator-1.10/LICENSE.MIT 2018-01-19 13:51:28.000000000
+0100
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/MANIFEST.in
new/async_generator-1.10/MANIFEST.in
--- old/async_generator-1.9/MANIFEST.in 2016-07-03 12:38:08.000000000 +0200
+++ new/async_generator-1.10/MANIFEST.in 2018-08-01 05:20:18.000000000
+0200
@@ -1,2 +1,6 @@
-include LICENSE.txt README.rst CODE_OF_CONDUCT.md
+include LICENSE LICENSE.MIT LICENSE.APACHE2
+include README.rst
+include CODE_OF_CONDUCT.md CONTRIBUTING.md
include test-requirements.txt .coveragerc
+recursive-include docs *
+prune docs/build
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/PKG-INFO
new/async_generator-1.10/PKG-INFO
--- old/async_generator-1.9/PKG-INFO 2018-01-19 13:35:44.000000000 +0100
+++ new/async_generator-1.10/PKG-INFO 2018-08-01 05:36:14.000000000 +0200
@@ -1,12 +1,11 @@
Metadata-Version: 1.2
Name: async_generator
-Version: 1.9
+Version: 1.10
Summary: Async generators and context managers for Python 3.5+
Home-page: https://github.com/python-trio/async_generator
Author: Nathaniel J. Smith
Author-email: [email protected]
-License: MIT
-Description-Content-Type: UNKNOWN
+License: MIT -or- Apache License 2.0
Description: .. image:: https://img.shields.io/badge/chat-join%20now-blue.svg
:target: https://gitter.im/python-trio/general
:alt: Join chatroom
@@ -15,16 +14,16 @@
:target:
https://async-generator.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
- .. image::
https://travis-ci.org/njsmith/async_generator.svg?branch=master
- :target: https://travis-ci.org/njsmith/async_generator
+ .. image::
https://travis-ci.org/python-trio/async_generator.svg?branch=master
+ :target: https://travis-ci.org/python-trio/async_generator
:alt: Automated test status
.. image::
https://ci.appveyor.com/api/projects/status/af4eyed8o8tc3t0r/branch/master?svg=true
:target: https://ci.appveyor.com/project/python-trio/trio/history
:alt: Automated test status (Windows)
- .. image::
https://codecov.io/gh/njsmith/async_generator/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/njsmith/async_generator
+ .. image::
https://codecov.io/gh/python-trio/async_generator/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/python-trio/async_generator
:alt: Test coverage
The async_generator library
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/README.rst
new/async_generator-1.10/README.rst
--- old/async_generator-1.9/README.rst 2018-01-19 11:14:22.000000000 +0100
+++ new/async_generator-1.10/README.rst 2018-04-23 10:59:12.000000000 +0200
@@ -6,16 +6,16 @@
:target: https://async-generator.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
-.. image:: https://travis-ci.org/njsmith/async_generator.svg?branch=master
- :target: https://travis-ci.org/njsmith/async_generator
+.. image:: https://travis-ci.org/python-trio/async_generator.svg?branch=master
+ :target: https://travis-ci.org/python-trio/async_generator
:alt: Automated test status
.. image::
https://ci.appveyor.com/api/projects/status/af4eyed8o8tc3t0r/branch/master?svg=true
:target: https://ci.appveyor.com/project/python-trio/trio/history
:alt: Automated test status (Windows)
-.. image::
https://codecov.io/gh/njsmith/async_generator/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/njsmith/async_generator
+.. image::
https://codecov.io/gh/python-trio/async_generator/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/python-trio/async_generator
:alt: Test coverage
The async_generator library
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/async_generator/__init__.py
new/async_generator-1.10/async_generator/__init__.py
--- old/async_generator-1.9/async_generator/__init__.py 2018-01-19
12:03:20.000000000 +0100
+++ new/async_generator-1.10/async_generator/__init__.py 2018-04-23
10:59:12.000000000 +0200
@@ -5,6 +5,8 @@
yield_from_,
isasyncgen,
isasyncgenfunction,
+ get_asyncgen_hooks,
+ set_asyncgen_hooks,
)
from ._util import aclosing, asynccontextmanager
@@ -16,4 +18,6 @@
"isasyncgen",
"isasyncgenfunction",
"asynccontextmanager",
+ "get_asyncgen_hooks",
+ "set_asyncgen_hooks",
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/async_generator/_impl.py
new/async_generator-1.10/async_generator/_impl.py
--- old/async_generator-1.9/async_generator/_impl.py 2018-01-19
12:40:10.000000000 +0100
+++ new/async_generator-1.10/async_generator/_impl.py 2018-04-23
10:59:12.000000000 +0200
@@ -45,7 +45,7 @@
# # We used to call _PyAsyncGenValueWrapperNew to create and set up new
# # wrapper objects, but that symbol isn't available on Windows:
# #
-# # https://github.com/njsmith/async_generator/issues/5
+# # https://github.com/python-trio/async_generator/issues/5
# #
# # Fortunately, the type object is available, but it means we have to do
# # this the hard way.
@@ -225,11 +225,76 @@
return result
+UNSPECIFIED = object()
+try:
+ from sys import get_asyncgen_hooks, set_asyncgen_hooks
+
+except ImportError:
+ import threading
+
+ asyncgen_hooks = collections.namedtuple(
+ "asyncgen_hooks", ("firstiter", "finalizer")
+ )
+
+ class _hooks_storage(threading.local):
+ def __init__(self):
+ self.firstiter = None
+ self.finalizer = None
+
+ _hooks = _hooks_storage()
+
+ def get_asyncgen_hooks():
+ return asyncgen_hooks(
+ firstiter=_hooks.firstiter, finalizer=_hooks.finalizer
+ )
+
+ def set_asyncgen_hooks(firstiter=UNSPECIFIED, finalizer=UNSPECIFIED):
+ if firstiter is not UNSPECIFIED:
+ if firstiter is None or callable(firstiter):
+ _hooks.firstiter = firstiter
+ else:
+ raise TypeError(
+ "callable firstiter expected, got {}".format(
+ type(firstiter).__name__
+ )
+ )
+
+ if finalizer is not UNSPECIFIED:
+ if finalizer is None or callable(finalizer):
+ _hooks.finalizer = finalizer
+ else:
+ raise TypeError(
+ "callable finalizer expected, got {}".format(
+ type(finalizer).__name__
+ )
+ )
+
+
class AsyncGenerator:
+ # https://bitbucket.org/pypy/pypy/issues/2786:
+ # PyPy implements 'await' in a way that requires the frame object
+ # used to execute a coroutine to keep a weakref to that coroutine.
+ # During a GC pass, weakrefs to all doomed objects are broken
+ # before any of the doomed objects' finalizers are invoked.
+ # If an AsyncGenerator is unreachable, its _coroutine probably
+ # is too, and the weakref from ag._coroutine.cr_frame to
+ # ag._coroutine will be broken before ag.__del__ can do its
+ # one-turn close attempt or can schedule a full aclose() using
+ # the registered finalization hook. It doesn't look like the
+ # underlying issue is likely to be fully fixed anytime soon,
+ # so we work around it by preventing an AsyncGenerator and
+ # its _coroutine from being considered newly unreachable at
+ # the same time if the AsyncGenerator's finalizer might want
+ # to iterate the coroutine some more.
+ _pypy_issue2786_workaround = set()
+
def __init__(self, coroutine):
self._coroutine = coroutine
self._it = coroutine.__await__()
self.ag_running = False
+ self._finalizer = None
+ self._closed = False
+ self._hooks_inited = False
# On python 3.5.0 and 3.5.1, __aiter__ must be awaitable.
# Starting in 3.5.2, it should not be awaitable, and if it is, then it
@@ -263,33 +328,49 @@
# Core functionality
################################################################
- # We make these async functions and use await, rather than just regular
- # functions that pass back awaitables, in order to get more useful
- # tracebacks when debugging.
+ # These need to return awaitables, rather than being async functions,
+ # to match the native behavior where the firstiter hook is called
+ # immediately on asend()/etc, even if the coroutine that asend()
+ # produces isn't awaited for a bit.
+
+ def __anext__(self):
+ return self._do_it(self._it.__next__)
+
+ def asend(self, value):
+ return self._do_it(self._it.send, value)
+
+ def athrow(self, type, value=None, traceback=None):
+ return self._do_it(self._it.throw, type, value, traceback)
+
+ def _do_it(self, start_fn, *args):
+ if not self._hooks_inited:
+ self._hooks_inited = True
+ (firstiter, self._finalizer) = get_asyncgen_hooks()
+ if firstiter is not None:
+ firstiter(self)
+ if sys.implementation.name == "pypy":
+ self._pypy_issue2786_workaround.add(self._coroutine)
- async def __anext__(self):
- return await self._do_it(self._it.__next__)
-
- async def asend(self, value):
- return await self._do_it(self._it.send, value)
-
- async def athrow(self, type, value=None, traceback=None):
- return await self._do_it(self._it.throw, type, value, traceback)
-
- async def _do_it(self, start_fn, *args):
# On CPython 3.5.2 (but not 3.5.0), coroutines get cranky if you try
# to iterate them after they're exhausted. Generators OTOH just raise
# StopIteration. We want to convert the one into the other, so we need
# to avoid iterating stopped coroutines.
if getcoroutinestate(self._coroutine) is CORO_CLOSED:
raise StopAsyncIteration()
- if self.ag_running:
- raise ValueError("async generator already executing")
- try:
- self.ag_running = True
- return await ANextIter(self._it, start_fn, *args)
- finally:
- self.ag_running = False
+
+ async def step():
+ if self.ag_running:
+ raise ValueError("async generator already executing")
+ try:
+ self.ag_running = True
+ return await ANextIter(self._it, start_fn, *args)
+ except StopAsyncIteration:
+ self._pypy_issue2786_workaround.discard(self._coroutine)
+ raise
+ finally:
+ self.ag_running = False
+
+ return step()
################################################################
# Cleanup
@@ -297,32 +378,54 @@
async def aclose(self):
state = getcoroutinestate(self._coroutine)
+ if state is CORO_CLOSED or self._closed:
+ return
+ # Make sure that even if we raise "async_generator ignored
+ # GeneratorExit", and thus fail to exhaust the coroutine,
+ # __del__ doesn't complain again.
+ self._closed = True
if state is CORO_CREATED:
# Make sure that aclose() on an unstarted generator returns
# successfully and prevents future iteration.
self._it.close()
return
- elif state is CORO_CLOSED:
- return
try:
await self.athrow(GeneratorExit)
except (GeneratorExit, StopAsyncIteration):
- pass
+ self._pypy_issue2786_workaround.discard(self._coroutine)
else:
raise RuntimeError("async_generator ignored GeneratorExit")
def __del__(self):
+ self._pypy_issue2786_workaround.discard(self._coroutine)
if getcoroutinestate(self._coroutine) is CORO_CREATED:
# Never started, nothing to clean up, just suppress the "coroutine
# never awaited" message.
self._coroutine.close()
- if getcoroutinestate(self._coroutine) is CORO_SUSPENDED:
- # This exception will get swallowed because this is __del__, but
- # it's an easy way to trigger the print-to-console logic
- raise RuntimeError(
- "partially-exhausted async_generator {!r} garbage collected"
- .format(self._coroutine.cr_frame.f_code.co_name)
- )
+ if getcoroutinestate(self._coroutine
+ ) is CORO_SUSPENDED and not self._closed:
+ if self._finalizer is not None:
+ self._finalizer(self)
+ else:
+ # Mimic the behavior of native generators on GC with no
finalizer:
+ # throw in GeneratorExit, run for one turn, and complain if it
didn't
+ # finish.
+ thrower = self.athrow(GeneratorExit)
+ try:
+ thrower.send(None)
+ except (GeneratorExit, StopAsyncIteration):
+ pass
+ except StopIteration:
+ raise RuntimeError("async_generator ignored GeneratorExit")
+ else:
+ raise RuntimeError(
+ "async_generator {!r} awaited during finalization;
install "
+ "a finalization hook to support this, or wrap it in "
+ "'async with aclosing(...):'"
+ .format(self.ag_code.co_name)
+ )
+ finally:
+ thrower.close()
if hasattr(collections.abc, "AsyncGenerator"):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/async_generator-1.9/async_generator/_tests/test_async_generator.py
new/async_generator-1.10/async_generator/_tests/test_async_generator.py
--- old/async_generator-1.9/async_generator/_tests/test_async_generator.py
2018-01-19 13:01:30.000000000 +0100
+++ new/async_generator-1.10/async_generator/_tests/test_async_generator.py
2018-04-23 10:59:12.000000000 +0200
@@ -13,6 +13,8 @@
yield_from_,
isasyncgen,
isasyncgenfunction,
+ get_asyncgen_hooks,
+ set_asyncgen_hooks,
)
@@ -190,6 +192,22 @@
pass # pragma: no cover
+async def test_reentrance_forbidden_simultaneous_asends():
+ @async_generator
+ async def f():
+ await mock_sleep()
+
+ ag = f()
+ sender1 = ag.asend(None)
+ sender2 = ag.asend(None)
+ assert sender1.send(None) == "mock_sleep"
+ with pytest.raises(ValueError):
+ sender2.send(None)
+ with pytest.raises(StopAsyncIteration):
+ sender1.send(None)
+ await ag.aclose()
+
+
# https://bugs.python.org/issue32526
async def test_reentrance_forbidden_while_suspended_in_coroutine_runner():
@async_generator
@@ -601,31 +619,68 @@
################################################################
-async def test___del__():
- gen = async_range(10)
+async def test___del__(capfd):
+ completions = 0
+
+ @async_generator
+ async def awaits_when_unwinding():
+ await yield_(0)
+ try:
+ await yield_(1)
+ finally:
+ await mock_sleep()
+ try:
+ await yield_(2)
+ finally:
+ nonlocal completions
+ completions += 1
+
+ gen = awaits_when_unwinding()
# Hasn't started yet, so no problem
gen.__del__()
- gen = async_range(10)
- await collect(gen)
+ gen = awaits_when_unwinding()
+ assert await collect(gen) == [0, 1, 2]
# Exhausted, so no problem
gen.__del__()
- gen = async_range(10)
- await gen.aclose()
- # Closed, so no problem
- gen.__del__()
+ for stop_after_turn in (1, 2, 3):
+ gen = awaits_when_unwinding()
+ for turn in range(stop_after_turn):
+ assert await gen.__anext__() == turn
+ await gen.aclose()
+ # Closed, so no problem
+ gen.__del__()
- gen = async_range(10)
- await gen.__anext__()
- await gen.aclose()
- # Closed, so no problem
- gen.__del__()
+ for stop_after_turn in (1, 2, 3):
+ gen = awaits_when_unwinding()
+ for turn in range(stop_after_turn):
+ assert await gen.__anext__() == turn
+
+ if stop_after_turn == 2:
+ # Stopped in the middle of a try/finally that awaits in the
finally,
+ # so __del__ can't cleanup.
+ with pytest.raises(RuntimeError) as info:
+ gen.__del__()
+ assert "awaited during finalization; install a finalization hook"
in str(
+ info.value
+ )
+ else:
+ # Can clean up without awaiting, so __del__ is fine
+ gen.__del__()
- gen = async_range(10)
- await gen.__anext__()
- # Started, but not exhausted or closed -- big problem
- with pytest.raises(RuntimeError):
+ assert completions == 3
+
+ @async_generator
+ async def yields_when_unwinding():
+ try:
+ await yield_(1)
+ finally:
+ await yield_(2)
+
+ gen = yields_when_unwinding()
+ assert await gen.__anext__() == 1
+ with pytest.raises(RuntimeError) as info:
gen.__del__()
@@ -779,3 +834,182 @@
for msg in recwarn: # pragma: no cover
print(msg)
assert not issubclass(msg.category, RuntimeWarning)
+
+
+################################################################
+#
+# GC hooks
+#
+################################################################
+
+
[email protected]
+def local_asyncgen_hooks():
+ old_hooks = get_asyncgen_hooks()
+ yield
+ set_asyncgen_hooks(*old_hooks)
+
+
+def test_gc_hooks_interface(local_asyncgen_hooks):
+ def one(agen): # pragma: no cover
+ pass
+
+ def two(agen): # pragma: no cover
+ pass
+
+ set_asyncgen_hooks(None, None)
+ assert get_asyncgen_hooks() == (None, None)
+ set_asyncgen_hooks(finalizer=two)
+ assert get_asyncgen_hooks() == (None, two)
+ set_asyncgen_hooks(firstiter=one)
+ assert get_asyncgen_hooks() == (one, two)
+ set_asyncgen_hooks(finalizer=None, firstiter=two)
+ assert get_asyncgen_hooks() == (two, None)
+ set_asyncgen_hooks(None, one)
+ assert get_asyncgen_hooks() == (None, one)
+ tup = (one, two)
+ set_asyncgen_hooks(*tup)
+ assert get_asyncgen_hooks() == tup
+
+ with pytest.raises(TypeError):
+ set_asyncgen_hooks(firstiter=42)
+
+ with pytest.raises(TypeError):
+ set_asyncgen_hooks(finalizer=False)
+
+ def in_thread(results):
+ results.append(get_asyncgen_hooks())
+ set_asyncgen_hooks(two, one)
+ results.append(get_asyncgen_hooks())
+
+ from threading import Thread
+ results = []
+ thread = Thread(target=in_thread, args=(results,))
+ thread.start()
+ thread.join()
+ assert results == [(None, None), (two, one)]
+ assert get_asyncgen_hooks() == (one, two)
+
+
+async def test_gc_hooks_behavior(local_asyncgen_hooks):
+ events = []
+ to_finalize = []
+
+ def firstiter(agen):
+ events.append("firstiter {}".format(agen.ag_frame.f_locals["ident"]))
+
+ def finalizer(agen):
+ events.append("finalizer {}".format(agen.ag_frame.f_locals["ident"]))
+ to_finalize.append(agen)
+
+ @async_generator
+ async def agen(ident):
+ events.append("yield 1 {}".format(ident))
+ await yield_(1)
+ try:
+ events.append("yield 2 {}".format(ident))
+ await yield_(2)
+ events.append("after yield 2 {}".format(ident))
+ finally:
+ events.append("mock_sleep {}".format(ident))
+ await mock_sleep()
+ try:
+ events.append("yield 3 {}".format(ident))
+ await yield_(3)
+ finally:
+ events.append("unwind 3 {}".format(ident))
+ # this one is included to make sure we _don't_ execute it
+ events.append("done {}".format(ident)) # pragma: no cover
+
+ async def anext_verbosely(iter, ident):
+ events.append("before asend {}".format(ident))
+ sender = iter.asend(None)
+ events.append("before send {}".format(ident))
+ await sender
+ events.append("after asend {}".format(ident))
+
+ # Ensure that firstiter is called immediately on asend(),
+ # before the first turn of the coroutine that asend() returns,
+ # to match the behavior of native generators.
+ # Ensure that the firstiter that gets used is the one in effect
+ # at the time of that first call, rather than at the time of iteration.
+ iterA = agen("A")
+ iterB = agen("B")
+ await anext_verbosely(iterA, "A")
+ set_asyncgen_hooks(firstiter, finalizer)
+ await anext_verbosely(iterB, "B")
+ iterC = agen("C")
+ await anext_verbosely(iterC, "C")
+
+ assert events == [
+ "before asend A", "before send A", "yield 1 A", "after asend A",
+ "before asend B", "firstiter B", "before send B", "yield 1 B",
+ "after asend B", "before asend C", "firstiter C", "before send C",
+ "yield 1 C", "after asend C"
+ ]
+ del events[:]
+
+ # Ensure that firstiter is only called once, even if we create
+ # two asend() coroutines before iterating either of them.
+ iterX = agen("X")
+ sender1 = iterX.asend(None)
+ sender2 = iterX.asend(None)
+ events.append("before close")
+ sender1.close()
+ sender2.close()
+ await iterX.aclose()
+ assert events == ["firstiter X", "before close"]
+ del events[:]
+
+ from weakref import ref
+ refA, refB, refC = map(ref, (iterA, iterB, iterC))
+
+ # iterA uses the finalizer that was in effect when it started, i.e. no
finalizer
+ await iterA.__anext__()
+ await iterA.__anext__()
+ del iterA
+ # Do multiple GC passes since we're deliberately shielding the
+ # coroutine objects from the first pass due to PyPy issue 2786.
+ for _ in range(4):
+ gc.collect()
+ assert refA() is None
+ assert events == [
+ "yield 2 A", "after yield 2 A", "mock_sleep A", "yield 3 A",
+ "unwind 3 A"
+ ]
+ assert not to_finalize
+ del events[:]
+
+ # iterB and iterC do use our finalizer
+ await iterC.__anext__()
+ await iterB.__anext__()
+ await iterC.__anext__()
+ idB, idC = id(iterB), id(iterC)
+ del iterB
+ for _ in range(4):
+ gc.collect()
+ del iterC
+ for _ in range(4):
+ gc.collect()
+ assert events == [
+ "yield 2 C", "yield 2 B", "after yield 2 C", "mock_sleep C",
+ "yield 3 C", "finalizer B", "finalizer C"
+ ]
+ del events[:]
+
+ # finalizer invokes aclose() is not called again once the revived
reference drops
+ assert list(map(id, to_finalize)) == [idB, idC]
+ events.append("before aclose B")
+ await to_finalize[0].aclose()
+ events.append("before aclose C")
+ await to_finalize[1].aclose()
+ events.append("after aclose both")
+ del to_finalize[:]
+ for _ in range(4):
+ gc.collect()
+ assert refB() is None and refC() is None
+
+ assert events == [
+ "before aclose B", "mock_sleep B", "before aclose C", "unwind 3 C",
+ "after aclose both"
+ ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/async_generator/_version.py
new/async_generator-1.10/async_generator/_version.py
--- old/async_generator-1.9/async_generator/_version.py 2018-01-19
13:31:58.000000000 +0100
+++ new/async_generator-1.10/async_generator/_version.py 2018-08-01
05:35:59.000000000 +0200
@@ -1 +1 @@
-__version__ = "1.9"
+__version__ = "1.10"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/async_generator-1.9/async_generator.egg-info/PKG-INFO
new/async_generator-1.10/async_generator.egg-info/PKG-INFO
--- old/async_generator-1.9/async_generator.egg-info/PKG-INFO 2018-01-19
13:35:44.000000000 +0100
+++ new/async_generator-1.10/async_generator.egg-info/PKG-INFO 2018-08-01
05:36:14.000000000 +0200
@@ -1,12 +1,11 @@
Metadata-Version: 1.2
Name: async-generator
-Version: 1.9
+Version: 1.10
Summary: Async generators and context managers for Python 3.5+
Home-page: https://github.com/python-trio/async_generator
Author: Nathaniel J. Smith
Author-email: [email protected]
-License: MIT
-Description-Content-Type: UNKNOWN
+License: MIT -or- Apache License 2.0
Description: .. image:: https://img.shields.io/badge/chat-join%20now-blue.svg
:target: https://gitter.im/python-trio/general
:alt: Join chatroom
@@ -15,16 +14,16 @@
:target:
https://async-generator.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
- .. image::
https://travis-ci.org/njsmith/async_generator.svg?branch=master
- :target: https://travis-ci.org/njsmith/async_generator
+ .. image::
https://travis-ci.org/python-trio/async_generator.svg?branch=master
+ :target: https://travis-ci.org/python-trio/async_generator
:alt: Automated test status
.. image::
https://ci.appveyor.com/api/projects/status/af4eyed8o8tc3t0r/branch/master?svg=true
:target: https://ci.appveyor.com/project/python-trio/trio/history
:alt: Automated test status (Windows)
- .. image::
https://codecov.io/gh/njsmith/async_generator/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/njsmith/async_generator
+ .. image::
https://codecov.io/gh/python-trio/async_generator/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/python-trio/async_generator
:alt: Test coverage
The async_generator library
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/async_generator-1.9/async_generator.egg-info/SOURCES.txt
new/async_generator-1.10/async_generator.egg-info/SOURCES.txt
--- old/async_generator-1.9/async_generator.egg-info/SOURCES.txt
2018-01-19 13:35:44.000000000 +0100
+++ new/async_generator-1.10/async_generator.egg-info/SOURCES.txt
2018-08-01 05:36:14.000000000 +0200
@@ -1,5 +1,9 @@
.coveragerc
CODE_OF_CONDUCT.md
+CONTRIBUTING.md
+LICENSE
+LICENSE.APACHE2
+LICENSE.MIT
MANIFEST.in
README.rst
setup.py
@@ -15,4 +19,11 @@
async_generator/_tests/__init__.py
async_generator/_tests/conftest.py
async_generator/_tests/test_async_generator.py
-async_generator/_tests/test_util.py
\ No newline at end of file
+async_generator/_tests/test_util.py
+docs/Makefile
+docs/make.bat
+docs/source/conf.py
+docs/source/history.rst
+docs/source/index.rst
+docs/source/reference.rst
+docs/source/_static/.gitkeep
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/Makefile
new/async_generator-1.10/docs/Makefile
--- old/async_generator-1.9/docs/Makefile 1970-01-01 01:00:00.000000000
+0100
+++ new/async_generator-1.10/docs/Makefile 2018-01-19 13:51:28.000000000
+0100
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+SPHINXPROJ = async_generator
+SOURCEDIR = source
+BUILDDIR = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/make.bat
new/async_generator-1.10/docs/make.bat
--- old/async_generator-1.9/docs/make.bat 1970-01-01 01:00:00.000000000
+0100
+++ new/async_generator-1.10/docs/make.bat 2018-01-19 13:51:28.000000000
+0100
@@ -0,0 +1,36 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+set SPHINXPROJ=async_generator
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively
you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
+
+:end
+popd
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/source/conf.py
new/async_generator-1.10/docs/source/conf.py
--- old/async_generator-1.9/docs/source/conf.py 1970-01-01 01:00:00.000000000
+0100
+++ new/async_generator-1.10/docs/source/conf.py 2018-01-19
13:51:28.000000000 +0100
@@ -0,0 +1,196 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Documentation build configuration file, created by
+# sphinx-quickstart on Sat Jan 21 19:11:14 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+# So autodoc can import our package
+sys.path.insert(0, os.path.abspath('../..'))
+
+# Warn about all references to unknown targets
+nitpicky = True
+# Except for these ones, which we expect to point to unknown targets:
+nitpick_ignore = [
+ # Format is ("sphinx reference type", "string"), e.g.:
+ ("py:obj", "bytes-like"),
+]
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.coverage',
+ 'sphinx.ext.napoleon',
+ 'sphinxcontrib_trio',
+]
+
+intersphinx_mapping = {
+ # 3.7 so that we can link to contextlib.asynccontextmanager
+ # This URL can switch back to /3 after cpython 3.7 is released
+ "python": ('https://docs.python.org/3.7', None),
+ "trio": ('https://trio.readthedocs.io/en/stable', None),
+}
+
+autodoc_member_order = "bysource"
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = []
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'async_generator'
+copyright = 'The async_generator authors'
+author = 'The async_generator authors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+import async_generator
+version = async_generator.__version__
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# The default language for :: blocks
+highlight_language = 'python3'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+#html_theme = 'alabaster'
+
+# We have to set this ourselves, not only because it's useful for local
+# testing, but also because if we don't then RTD will throw away our
+# html_theme_options.
+import sphinx_rtd_theme
+html_theme = 'sphinx_rtd_theme'
+html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+html_theme_options = {
+ # default is 2
+ # show deeper nesting in the RTD theme's sidebar TOC
+ # https://stackoverflow.com/questions/27669376/
+ # I'm not 100% sure this actually does anything with our current
+ # versions/settings...
+ "navigation_depth": 4,
+ "logo_only": True,
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'async_generatordoc'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'async_generator.tex', 'Trio Documentation',
+ author, 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'async_generator', 'async_generator Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'async_generator', 'async_generator Documentation',
+ author, 'async_generator', 'A short description of the project (for
setup.py metadata)',
+ 'Miscellaneous'),
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/source/history.rst
new/async_generator-1.10/docs/source/history.rst
--- old/async_generator-1.9/docs/source/history.rst 1970-01-01
01:00:00.000000000 +0100
+++ new/async_generator-1.10/docs/source/history.rst 2018-08-01
05:29:57.000000000 +0200
@@ -0,0 +1,153 @@
+Release history
+===============
+
+.. currentmodule:: async_generator
+
+.. towncrier release notes start
+
+Async_Generator 1.10 (2018-07-31)
+---------------------------------
+
+Features
+~~~~~~~~
+
+- Add support for PEP 525-style finalization hooks via
+ ``set_asyncgen_hooks()`` and ``get_asyncgen_hooks()`` functions. On
+ Python 3.6+, these are aliases for the versions in ``sys``; on
+ Python 3.5, they're work-alike implementations. And,
+ ``@async_generator`` generators now call these hooks at the
+ appropriate times. (`#15
+ <https://github.com/python-trio/trio/issues/15>`__)
+
+Fixes
+~~~~~
+
+- Package now properly includes license files. (`#11
+ <https://github.com/python-trio/async_generator/pull/11>`__)
+
+
+1.9 (2018-01-19)
+----------------
+
+* Add :func:`asynccontextmanager`
+* When a partially-exhausted ``async_generator`` is garbage collected,
+ the warning printed now includes the generator's name to help you
+ track it down.
+* Move under the auspices of the Trio project. This includes a license
+ change from MIT → dual MIT+Apache2, and various changes to internal
+ organization to match Trio project standard.
+
+1.8 (2017-06-17)
+----------------
+
+* Implement PEP 479: if a ``StopAsyncIteration`` leaks out of an async
+ generator body, wrap it into a ``RuntimeError``.
+* If an async generator was instantiated but never iterated, then we
+ used to issue a spurious "RuntimeWarning: coroutine '...' was never
+ awaited" warning. This is now fixed.
+* Add PyPy3 to our test matrix.
+* 100% test coverage.
+
+
+1.7 (2017-05-13)
+----------------
+
+* Fix a subtle bug where if you wrapped an async generator using
+ ``functools.wraps``, then ``isasyncgenfunction`` would return True
+ for the wrapper. This isn't how ``inspect.isasyncgenfunction``
+ works, and it broke ``sphinxcontrib_trio``.
+
+
+1.6 (2017-02-17)
+----------------
+
+* Add support for async generator introspection attributes
+ ``ag_running``, ``ag_code``, ``ag_frame``.
+* Attempting to re-enter a running async_generator now raises
+ ``ValueError``, just like for native async generators.
+* 100% test coverage.
+
+
+1.5 (2017-01-15)
+----------------
+
+* Remove (temporarily?) the hacks that let ``yield_`` and
+ ``yield_from_`` work with native async generators. It turns out that
+ due to obscure linking issues this was causing the library to be
+ entirely broken on Python 3.6 on Windows (but not Linux or
+ MacOS). It's probably fixable, but needs some fiddling with ctypes
+ to get the refcounting right, and I couldn't figure it out in the
+ time I had available to spend.
+
+ So in this version, everything that worked before still works with
+ ``@async_generator``-style generators, but uniformly, on all
+ platforms, ``yield_`` and ``yield_from_`` now do *not* work inside
+ native-style async generators.
+* Now running CI testing on Windows as well as Linux.
+* 100% test coverage.
+
+
+1.4 (2016-12-05)
+----------------
+
+* Allow ``await yield_()`` as an shorthand for ``await yield_(None)``
+ (thanks to Alex Grönholm for the suggestion+patch).
+* Small cleanups to setup.py and test infrastructure.
+* 100% test coverage (now including branch coverage!)
+
+
+1.3 (2016-11-24)
+----------------
+
+* Added ``isasyncgen`` and ``isasyncgenfunction``.
+* On 3.6+, register our async generators with
+ ``collections.abc.AsyncGenerator``.
+* 100% test coverage.
+
+
+1.2 (2016-11-14)
+----------------
+
+* Rewrote ``yield from`` support; now has much more accurate handling
+ of edge cases.
+* ``yield_from_`` now works inside CPython 3.6's native async
+ generators.
+* Added ``aclosing`` context manager; it's pretty trivial, but if
+ we're going to recommend it be used everywhere then it seems polite
+ to include it.
+* 100% test coverage.
+
+
+1.1 (2016-11-06)
+----------------
+
+* Support for ``asend``\/``athrow``\/``aclose``
+* Support for ``yield from``
+* Add a ``__del__`` method that complains about improperly cleaned up
+ async generators.
+* Adapt to `the change in Python 3.5.2
+
<https://www.python.org/dev/peps/pep-0492/#api-design-and-implementation-revisions>`_
+ where ``__aiter__`` should now be a regular method instead of an
+ async method.
+* Adapt to Python 3.5.2's pickiness about iterating over
+ already-exhausted coroutines.
+* 100% test coverage.
+
+
+1.0 (2016-07-03)
+----------------
+
+* Fixes a very nasty and hard-to-hit bug where ``await yield_(...)``
+ calls could escape out to the top-level coroutine runner and get
+ lost, if the last trap out to the coroutine runner before the
+ ``await yield_(...)`` caused an exception to be injected.
+* Infinitesimally more efficient due to re-using internal
+ ``ANextIter`` objects instead of recreating them on each call to
+ ``__anext__``.
+* 100% test coverage.
+
+
+0.0.1 (2016-05-31)
+------------------
+
+Initial release.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/source/index.rst
new/async_generator-1.10/docs/source/index.rst
--- old/async_generator-1.9/docs/source/index.rst 1970-01-01
01:00:00.000000000 +0100
+++ new/async_generator-1.10/docs/source/index.rst 2018-01-19
13:51:28.000000000 +0100
@@ -0,0 +1,24 @@
+.. documentation master file, created by
+ sphinx-quickstart on Sat Jan 21 19:11:14 2017.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+
+=====================================================================
+async_generator: Async generators and related tools for older Pythons
+=====================================================================
+
+.. toctree::
+ :maxdepth: 2
+
+ reference.rst
+ history.rst
+
+====================
+ Indices and tables
+====================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+* :ref:`glossary`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/docs/source/reference.rst
new/async_generator-1.10/docs/source/reference.rst
--- old/async_generator-1.9/docs/source/reference.rst 1970-01-01
01:00:00.000000000 +0100
+++ new/async_generator-1.10/docs/source/reference.rst 2018-04-23
10:59:12.000000000 +0200
@@ -0,0 +1,187 @@
+API documentation
+=================
+
+Async generators
+----------------
+
+In Python 3.6+, you can write a native async generator like this::
+
+ async def load_json_lines(stream_reader):
+ async for line in stream_reader:
+ yield json.loads(line)
+
+Here's the same thing written with this library, which works on Python 3.5+::
+
+ from async_generator import async_generator, yield
+
+ @async_generator
+ async def load_json_lines(stream_reader):
+ async for line in stream_reader:
+ await yield_(json.loads(line))
+
+Basically:
+
+* decorate your function with ``@async_generator``
+* replace ``yield`` with ``await yield_()``
+* replace ``yield X`` with ``await yield_(X)``
+
+That's it!
+
+
+Yield from
+~~~~~~~~~~
+
+Native async generators don't support ``yield from``::
+
+ # Doesn't work!
+ async def wrap_load_json_lines(stream_reader):
+ # This is a SyntaxError
+ yield from load_json_lines(stream_reader)
+
+But we do::
+
+ from async_generator import async_generator, yield_from_
+
+ # This works!
+ @async_generator
+ async def wrap_load_json_lines(stream_reader):
+ await yield_from_(load_json_lines(stream_reader))
+
+You can only use ``yield_from_`` inside an ``@async_generator``
+function, BUT the thing you PASS to ``yield_from_`` can be any kind of
+async iterator, including native async generators.
+
+Our ``yield_from_`` fully supports the classic ``yield from``
+semantics, including forwarding ``asend`` and ``athrow`` calls into
+the delegated async generator, and returning values::
+
+ from async_generator import async_generator, yield_, yield_from_
+
+ @async_generator
+ async def agen1():
+ await yield_(1)
+ await yield_(2)
+ return "great!"
+
+ @async_generator
+ async def agen2():
+ value = await yield_from_(agen1())
+ assert value == "great!"
+
+
+Introspection
+~~~~~~~~~~~~~
+
+For introspection purposes, we also export the following functions:
+
+.. function:: isasyncgen(agen_obj)
+
+ Returns true if passed either an async generator object created by
+ this library, or a native Python 3.6+ async generator object.
+ Analogous to :func:`inspect.isasyncgen` in 3.6+.
+
+.. function:: isasyncgenfunction(agen_func)
+
+ Returns true if passed either an async generator function created
+ by this library, or a native Python 3.6+ async generator function.
+ Analogous to :func:`inspect.isasyncgenfunction` in 3.6+.
+
+Example::
+
+ >>> isasyncgenfunction(load_json_lines)
+ True
+ >>> gen_object = load_json_lines(asyncio_stream_reader)
+ >>> isasyncgen(gen_object)
+ True
+
+In addition, this library's async generator objects are registered
+with the ``collections.abc.AsyncGenerator`` abstract base class (if
+available)::
+
+ >>> isinstance(gen_object, collections.abc.AsyncGenerator)
+ True
+
+
+Semantics
+~~~~~~~~~
+
+This library generally tries hard to match the semantics of Python
+3.6's native async generators in every detail (`PEP 525
+<https://www.python.org/dev/peps/pep-0525/>`__), with additional
+support for ``yield from`` and for returning non-None values from
+an async generator (under the theory that these may well be added
+to native async generators one day).
+
+
+Garbage collection hooks
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This library fully supports the native async generator
+`finalization semantics
<https://www.python.org/dev/peps/pep-0525/#finalization>`__,
+including the per-thread ``firstiter`` and ``finalizer`` hooks.
+You can use ``async_generator.set_asyncgen_hooks()`` exactly
+like you would use ``sys.set_asyncgen_hooks()`` with native
+generators. On Python 3.6+, the former is an alias for the latter,
+so libraries that use the native mechanism should work seamlessly
+with ``@async_generator`` functions. On Python 3.5, where there is
+no ``sys.set_asyncgen_hooks()``, most libraries probably *won't* know
+about ``async_generator.set_asyncgen_hooks()``, so you'll need
+to exercise more care with explicit cleanup, or install appropriate
+hooks yourself.
+
+While finishing cleanup of an async generator is better than dropping
+it on the floor at the first ``await``, it's still not a perfect solution;
+in addition to the unpredictability of GC timing, the ``finalizer`` hook
+has no practical way to determine the context in which the generator was
+being iterated, so an exception thrown from the generator during ``aclose()``
+must either crash the program or get discarded. It's much better to close
+your generators explicitly when you're done with them, perhaps using the
+:ref:`aclosing context manager <contextmanagers>`. See `this discussion
+<https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/#cleanup-in-generators-and-async-generators>`__
+and `PEP 533 <https://www.python.org/dev/peps/pep-0533/>`__ for more
+details.
+
+
+.. _contextmanagers:
+
+Context managers
+----------------
+
+As discussed above, you should always explicitly call ``aclose`` on
+async generators. To make this more convenient, this library also
+includes an ``aclosing`` async context manager. It acts just like the
+``closing`` context manager included in the stdlib ``contextlib``
+module, but does ``await obj.aclose()`` instead of
+``obj.close()``. Use it like this::
+
+ from async_generator import aclosing
+
+ async with aclosing(load_json_lines(asyncio_stream_reader)) as agen:
+ async for json_obj in agen:
+ ...
+
+Or if you want to write your own async context managers, we've got you
+covered:
+
+.. function:: asynccontextmanager
+ :decorator:
+
+ This is a backport of :func:`contextlib.asynccontextmanager`, which
+ wasn't added to the standard library until Python 3.7.
+
+You can use ``@asynccontextmanager`` with either native async
+generators, or the ones from this package. If you use it with the ones
+from this package, remember that ``@asynccontextmanager`` goes *on
+top* of ``@async_generator``::
+
+ # Correct!
+ @asynccontextmanager
+ @async_generator
+ async def my_async_context_manager():
+ ...
+
+ # This won't work :-(
+ @async_generator
+ @asynccontextmanager
+ async def my_async_context_manager():
+ ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/async_generator-1.9/setup.py
new/async_generator-1.10/setup.py
--- old/async_generator-1.9/setup.py 2018-01-19 11:33:29.000000000 +0100
+++ new/async_generator-1.10/setup.py 2018-08-01 05:20:18.000000000 +0200
@@ -13,7 +13,7 @@
long_description=Path(__file__).with_name("README.rst").read_text('utf-8'),
author="Nathaniel J. Smith",
author_email="[email protected]",
- license="MIT",
+ license="MIT -or- Apache License 2.0",
packages=find_packages(),
url="https://github.com/python-trio/async_generator",
python_requires=">=3.5",