Update zaza/__init__.py from zaza (#750)

The zaza and zaza-openstack-tests project are currently installed
within the same package.  A side effect of that is that the
zaza/__init__.py from zaza is overwritten by the one in
zaza-openstack-tests.

We ought to find a better way of doing this but we're currently
blocked on using zaza + zaza-openstack-tests on systems with
Python 3.10 installed, and updating this file unblocks us.

Update zaza/__init__.py from openstack-charmers/zaza@c48c955ef7
This commit is contained in:
Frode Nordahl
2022-04-13 15:36:03 +02:00
committed by GitHub
parent c0d1a73259
commit 68eb4f482a
+63 -3
View File
@@ -12,9 +12,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# __NOTE__
#
# Whenever this file is changed, make sure to update the copy of it in
# ``zaza-openstack-tests``.
#
# The ``zaza`` and ``zaza-openstack-tests`` projects are related, and currently
# the latter is installed as a package inside the former. As a consequence
# ``zaza-openstack-tests`` needs to carry a copy of this file
# (``zaza/__init__.py``) as this file will be overwritten by the copy in
# ``zaza-openstack-tests`` on install.
#
# We of course want a better solution to this, but in the interest of time
# this note is left here until we get around to fixing it properly.
#
# __NOTE__
"""Functions to support converting async function to a sync equivalent."""
import asyncio
import logging
from pkgutil import extend_path
from sys import version_info
__path__ = extend_path(__path__, __name__)
@@ -23,22 +41,64 @@ __path__ = extend_path(__path__, __name__)
def run(*steps):
"""Run the given steps in an asyncio loop.
:returns: The result of the asyncio.Task
If the tasks spawns other future (tasks) then these are also cleaned up
after each step is performed.
:returns: The result of the last asyncio.Task
:rtype: Any
"""
if not steps:
return
loop = asyncio.get_event_loop()
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
except AttributeError:
# Remove once support for Python 3.6 is dropped
loop = asyncio.get_event_loop()
for step in steps:
task = loop.create_task(step)
loop.run_until_complete(asyncio.wait([task], loop=loop))
loop.run_until_complete(asyncio.wait([task]))
# Let's also cancel any remaining tasks:
while True:
# issue #445 - asyncio.Task.all_tasks() deprecated in 3.7
if version_info.major == 3 and version_info.minor >= 7:
try:
tasklist = asyncio.all_tasks()
except RuntimeError:
# no running event loop
break
else:
tasklist = asyncio.Task.all_tasks()
pending_tasks = [p for p in tasklist if not p.done()]
if pending_tasks:
logging.info(
"async -> sync. cleaning up pending tasks: len: {}"
.format(len(pending_tasks)))
for pending_task in pending_tasks:
pending_task.cancel()
try:
loop.run_until_complete(pending_task)
except asyncio.CancelledError:
pass
except Exception as e:
logging.error(
"A pending task caused an exception: {}"
.format(str(e)))
else:
break
return task.result()
def sync_wrapper(f):
"""Convert the given async function into a sync function.
This is only to be called from sync code and it runs all tasks (and cancels
all tasks at the end of each run) for the code that is being given.
:returns: The de-async'd function
:rtype: function
"""