mit neuen venv und exe-Files
This commit is contained in:
704
venv3_12/Lib/site-packages/gevent/monkey/__init__.py
Normal file
704
venv3_12/Lib/site-packages/gevent/monkey/__init__.py
Normal file
@@ -0,0 +1,704 @@
|
||||
# Copyright (c) 2009-2012 Denis Bilenko. See LICENSE for details.
|
||||
# pylint: disable=redefined-outer-name,too-many-lines
|
||||
"""
|
||||
Make the standard library cooperative.
|
||||
|
||||
The primary purpose of this module is to carefully patch, in place,
|
||||
portions of the standard library with gevent-friendly functions that
|
||||
behave in the same way as the original (at least as closely as possible).
|
||||
|
||||
The primary interface to this is the :func:`patch_all` function, which
|
||||
performs all the available patches. It accepts arguments to limit the
|
||||
patching to certain modules, but most programs **should** use the
|
||||
default values as they receive the most wide-spread testing, and some monkey
|
||||
patches have dependencies on others.
|
||||
|
||||
Patching **should be done as early as possible** in the lifecycle of the
|
||||
program. For example, the main module (the one that tests against
|
||||
``__main__`` or is otherwise the first imported) should begin with
|
||||
this code, ideally before any other imports::
|
||||
|
||||
from gevent import monkey
|
||||
monkey.patch_all()
|
||||
|
||||
A corollary of the above is that patching **should be done on the main
|
||||
thread** and **should be done while the program is single-threaded**.
|
||||
|
||||
.. tip::
|
||||
|
||||
Some frameworks, such as gunicorn, handle monkey-patching for you.
|
||||
Check their documentation to be sure.
|
||||
|
||||
.. warning::
|
||||
|
||||
Patching too late can lead to unreliable behaviour (for example, some
|
||||
modules may still use blocking sockets) or even errors.
|
||||
|
||||
.. tip::
|
||||
|
||||
Be sure to read the documentation for each patch function to check for
|
||||
known incompatibilities.
|
||||
|
||||
Querying
|
||||
========
|
||||
|
||||
Sometimes it is helpful to know if objects have been monkey-patched, and in
|
||||
advanced cases even to have access to the original standard library functions. This
|
||||
module provides functions for that purpose.
|
||||
|
||||
- :func:`is_module_patched`
|
||||
- :func:`is_object_patched`
|
||||
- :func:`get_original`
|
||||
|
||||
.. _plugins:
|
||||
|
||||
Plugins and Events
|
||||
==================
|
||||
|
||||
Beginning in gevent 1.3, events are emitted during the monkey patching process.
|
||||
These events are delivered first to :mod:`gevent.events` subscribers, and then
|
||||
to `setuptools entry points`_.
|
||||
|
||||
The following events are defined. They are listed in (roughly) the order
|
||||
that a call to :func:`patch_all` will emit them.
|
||||
|
||||
- :class:`gevent.events.GeventWillPatchAllEvent`
|
||||
- :class:`gevent.events.GeventWillPatchModuleEvent`
|
||||
- :class:`gevent.events.GeventDidPatchModuleEvent`
|
||||
- :class:`gevent.events.GeventDidPatchBuiltinModulesEvent`
|
||||
- :class:`gevent.events.GeventDidPatchAllEvent`
|
||||
|
||||
Each event class documents the corresponding setuptools entry point name. The
|
||||
entry points will be called with a single argument, the same instance of
|
||||
the class that was sent to the subscribers.
|
||||
|
||||
You can subscribe to the events to monitor the monkey-patching process and
|
||||
to manipulate it, for example by raising :exc:`gevent.events.DoNotPatch`.
|
||||
|
||||
You can also subscribe to the events to provide additional patching beyond what
|
||||
gevent distributes, either for additional standard library modules, or
|
||||
for third-party packages. The suggested time to do this patching is in
|
||||
the subscriber for :class:`gevent.events.GeventDidPatchBuiltinModulesEvent`.
|
||||
For example, to automatically patch `psycopg2`_ using `psycogreen`_
|
||||
when the call to :func:`patch_all` is made, you could write code like this::
|
||||
|
||||
# mypackage.py
|
||||
def patch_psycopg(event):
|
||||
from psycogreen.gevent import patch_psycopg
|
||||
patch_psycopg()
|
||||
|
||||
In your ``setup.py`` you would register it like this::
|
||||
|
||||
from setuptools import setup
|
||||
setup(
|
||||
...
|
||||
entry_points={
|
||||
'gevent.plugins.monkey.did_patch_builtins': [
|
||||
'psycopg2 = mypackage:patch_psycopg',
|
||||
],
|
||||
},
|
||||
...
|
||||
)
|
||||
|
||||
For more complex patching, gevent provides a helper method
|
||||
that you can call to replace attributes of modules with attributes of your
|
||||
own modules. This function also takes care of emitting the appropriate events.
|
||||
|
||||
- :func:`patch_module`
|
||||
|
||||
.. _setuptools entry points: http://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins
|
||||
.. _psycopg2: https://pypi.python.org/pypi/psycopg2
|
||||
.. _psycogreen: https://pypi.python.org/pypi/psycogreen
|
||||
|
||||
Use as a module
|
||||
===============
|
||||
|
||||
Sometimes it is useful to run existing python scripts or modules that
|
||||
were not built to be gevent aware under gevent. To do so, this module
|
||||
can be run as the main module, passing the script and its arguments.
|
||||
For details, see the :func:`main` function.
|
||||
|
||||
.. versionchanged:: 1.3b1
|
||||
Added support for plugins and began emitting will/did patch events.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
####
|
||||
# gevent developers: IMPORTANT: Keep imports
|
||||
# as limited and localized as possible to avoid
|
||||
# interfering with the monkey-patch process.
|
||||
# This is why many imports are nested inside functions.
|
||||
#
|
||||
# This applies for this entire package.
|
||||
###
|
||||
|
||||
__all__ = [
|
||||
'patch_all',
|
||||
'patch_builtins',
|
||||
'patch_dns',
|
||||
'patch_os',
|
||||
'patch_queue',
|
||||
'patch_select',
|
||||
'patch_signal',
|
||||
'patch_socket',
|
||||
'patch_ssl',
|
||||
'patch_subprocess',
|
||||
'patch_sys',
|
||||
'patch_thread',
|
||||
'patch_time',
|
||||
# query functions
|
||||
'get_original',
|
||||
'is_module_patched',
|
||||
'is_object_patched',
|
||||
|
||||
# 'is_anything_patched', <- see docstring
|
||||
|
||||
# plugin API
|
||||
'patch_module',
|
||||
# module functions
|
||||
'main',
|
||||
# Errors and warnings
|
||||
'MonkeyPatchWarning',
|
||||
]
|
||||
|
||||
WIN = sys.platform.startswith("win")
|
||||
|
||||
# Unused imports may be removed in a major release after 2024-10.
|
||||
# Used private imports may be renamed or removed or changed
|
||||
# in an incompatible way at that time.
|
||||
|
||||
|
||||
|
||||
from ._errors import MonkeyPatchWarning
|
||||
|
||||
from ._util import _notify_patch
|
||||
from ._util import _ignores_DoNotPatch
|
||||
|
||||
from ._state import saved
|
||||
from ._state import is_module_patched
|
||||
from ._state import is_object_patched
|
||||
|
||||
# Never documented as a public API, but
|
||||
# potentially in use by third parties
|
||||
# given the naming convention.
|
||||
from ._state import is_anything_patched # pylint:disable=unused-import
|
||||
from ._errors import _BadImplements # pylint:disable=unused-import
|
||||
|
||||
|
||||
|
||||
from .api import get_original
|
||||
from .api import patch_module
|
||||
|
||||
|
||||
|
||||
# These are not part of the documented public API,
|
||||
# but they could be used by plugins. TODO: Do we
|
||||
# want to make them public with __all__?
|
||||
from .api import patch_item
|
||||
from .api import remove_item
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
from ._util import _check_availability
|
||||
from ._util import _patch_module
|
||||
from ._util import _queue_warning
|
||||
from ._util import _process_warnings
|
||||
|
||||
|
||||
|
||||
def _patch_sys_std(name):
|
||||
from gevent.fileobject import FileObjectThread
|
||||
orig = getattr(sys, name)
|
||||
if not isinstance(orig, FileObjectThread):
|
||||
patch_item(sys, name, FileObjectThread(orig))
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_sys(stdin=True, stdout=True, stderr=True): # pylint:disable=unused-argument
|
||||
"""
|
||||
Patch sys.std[in,out,err] to use a cooperative IO via a
|
||||
threadpool.
|
||||
|
||||
This is relatively dangerous and can have unintended consequences
|
||||
such as hanging the process or `misinterpreting control keys`_
|
||||
when :func:`input` and :func:`raw_input` are used. :func:`patch_all`
|
||||
does *not* call this function by default.
|
||||
|
||||
This method does nothing on Python 3. The Python 3 interpreter
|
||||
wants to flush the TextIOWrapper objects that make up
|
||||
stderr/stdout at shutdown time, but using a threadpool at that
|
||||
time leads to a hang.
|
||||
|
||||
.. _`misinterpreting control keys`: https://github.com/gevent/gevent/issues/274
|
||||
|
||||
.. deprecated:: 23.7.0
|
||||
Does nothing on any supported version.
|
||||
"""
|
||||
return
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_os():
|
||||
"""
|
||||
Replace :func:`os.fork` with :func:`gevent.fork`, and, on POSIX,
|
||||
:func:`os.waitpid` with :func:`gevent.os.waitpid` (if the
|
||||
environment variable ``GEVENT_NOWAITPID`` is not defined). Does
|
||||
nothing if fork is not available.
|
||||
|
||||
.. caution:: This method must be used with :func:`patch_signal` to have proper `SIGCHLD`
|
||||
handling and thus correct results from ``waitpid``.
|
||||
:func:`patch_all` calls both by default.
|
||||
|
||||
.. caution:: For `SIGCHLD` handling to work correctly, the event loop must run.
|
||||
The easiest way to help ensure this is to use :func:`patch_all`.
|
||||
"""
|
||||
_patch_module('os')
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_queue():
|
||||
"""
|
||||
Patch objects in :mod:`queue`.
|
||||
|
||||
|
||||
Currently, this just replaces :class:`queue.SimpleQueue` (implemented
|
||||
in C) with its Python counterpart, but the details may change at any time.
|
||||
|
||||
.. versionadded:: 1.3.5
|
||||
"""
|
||||
_patch_module('queue', items=[
|
||||
'SimpleQueue',
|
||||
])
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_time():
|
||||
"""
|
||||
Replace :func:`time.sleep` with :func:`gevent.sleep`.
|
||||
"""
|
||||
_patch_module('time')
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_contextvars():
|
||||
"""
|
||||
Replaces the implementations of :mod:`contextvars` with
|
||||
:mod:`gevent.contextvars`.
|
||||
|
||||
On Python 3.7 and above, this is a standard library module. On
|
||||
earlier versions, a backport that uses the same distribution name
|
||||
and import name is available on PyPI (though this is not
|
||||
recommended). If that is installed, it will be patched.
|
||||
|
||||
.. versionchanged:: 20.04.0
|
||||
Clarify that the backport is also patched.
|
||||
|
||||
.. versionchanged:: 20.9.0
|
||||
This now does nothing on Python 3.7 and above.
|
||||
gevent now depends on greenlet 0.4.17, which
|
||||
natively handles switching context vars when greenlets are switched.
|
||||
Older versions of Python that have the backport installed will
|
||||
still be patched.
|
||||
|
||||
.. deprecated:: 23.7.0
|
||||
Does nothing on any supported version.
|
||||
"""
|
||||
return
|
||||
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_thread(threading=True, _threading_local=True, Event=True, logging=True,
|
||||
existing_locks=True,
|
||||
_warnings=None):
|
||||
"""
|
||||
patch_thread(threading=True, _threading_local=True, Event=True, logging=True, existing_locks=True) -> None
|
||||
|
||||
Replace the standard :mod:`thread` module to make it greenlet-based.
|
||||
|
||||
:keyword bool threading: When True (the default),
|
||||
also patch :mod:`threading`.
|
||||
:keyword bool _threading_local: When True (the default),
|
||||
also patch :class:`_threading_local.local`.
|
||||
:keyword bool logging: When True (the default), also patch locks
|
||||
taken if the logging module has been configured.
|
||||
|
||||
:keyword bool existing_locks: When True (the default), and the
|
||||
process is still single threaded, make sure that any
|
||||
:class:`threading.RLock` (and, under Python 3, :class:`importlib._bootstrap._ModuleLock`)
|
||||
instances that are currently locked can be properly unlocked. **Important**: This is a
|
||||
best-effort attempt and, on certain implementations, may not detect all
|
||||
locks. It is important to monkey-patch extremely early in the startup process.
|
||||
Setting this to False is not recommended, especially on Python 2.
|
||||
|
||||
.. caution::
|
||||
Monkey-patching :mod:`thread` and using
|
||||
:class:`multiprocessing.Queue` or
|
||||
:class:`concurrent.futures.ProcessPoolExecutor` (which uses a
|
||||
``Queue``) will hang the process.
|
||||
|
||||
Monkey-patching with this function and using
|
||||
sub-interpreters (and advanced C-level API) and threads may be
|
||||
unstable on certain platforms.
|
||||
|
||||
.. versionchanged:: 1.1b1
|
||||
Add *logging* and *existing_locks* params.
|
||||
.. versionchanged:: 1.3a2
|
||||
``Event`` defaults to True.
|
||||
"""
|
||||
if sys.version_info[:2] < (3, 13):
|
||||
from ._patch_thread_lt313 import Patcher
|
||||
else:
|
||||
from ._patch_thread_gte313 import Patcher
|
||||
patch = Patcher(threading=threading, _threading_local=_threading_local, Event=Event,
|
||||
logging=logging, existing_locks=existing_locks, _warnings=_warnings)
|
||||
patch()
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_socket(dns=True, aggressive=True):
|
||||
"""
|
||||
Replace the standard socket object with gevent's cooperative
|
||||
sockets.
|
||||
|
||||
:keyword bool dns: When true (the default), also patch address
|
||||
resolution functions in :mod:`socket`. See :doc:`/dns` for details.
|
||||
"""
|
||||
from gevent import socket
|
||||
# Note: although it seems like it's not strictly necessary to monkey patch 'create_connection',
|
||||
# it's better to do it. If 'create_connection' was not monkey patched, but the rest of socket module
|
||||
# was, create_connection would still use "green" getaddrinfo and "green" socket.
|
||||
# However, because gevent.socket.socket.connect is a Python function, the exception raised by it causes
|
||||
# _socket object to be referenced by the frame, thus causing the next invocation of bind(source_address) to fail.
|
||||
if dns:
|
||||
items = socket.__implements__ # pylint:disable=no-member
|
||||
else:
|
||||
items = set(socket.__implements__) - set(socket.__dns__) # pylint:disable=no-member
|
||||
_patch_module('socket', items=items)
|
||||
if aggressive:
|
||||
if 'ssl' not in socket.__implements__: # pylint:disable=no-member
|
||||
remove_item(socket, 'ssl')
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_dns():
|
||||
"""
|
||||
Replace :doc:`DNS functions </dns>` in :mod:`socket` with
|
||||
cooperative versions.
|
||||
|
||||
This is only useful if :func:`patch_socket` has been called and is
|
||||
done automatically by that method if requested.
|
||||
"""
|
||||
from gevent import socket
|
||||
_patch_module('socket', items=socket.__dns__) # pylint:disable=no-member
|
||||
|
||||
|
||||
def _find_module_refs(to, excluding_names=()):
|
||||
# Looks specifically for module-level references,
|
||||
# i.e., 'from foo import Bar'. We define a module reference
|
||||
# as a dict (subclass) that also has a __name__ attribute.
|
||||
# This does not handle subclasses, but it does find them.
|
||||
# Returns two sets. The first is modules (name, file) that were
|
||||
# found. The second is subclasses that were found.
|
||||
gc = __import__('gc')
|
||||
direct_ref_modules = set()
|
||||
subclass_modules = set()
|
||||
|
||||
def report(mod):
|
||||
return mod['__name__'], mod.get('__file__', '<unknown>')
|
||||
|
||||
for r in gc.get_referrers(to):
|
||||
if isinstance(r, dict) and '__name__' in r:
|
||||
if r['__name__'] in excluding_names:
|
||||
continue
|
||||
|
||||
for v in r.values():
|
||||
if v is to:
|
||||
direct_ref_modules.add(report(r))
|
||||
elif isinstance(r, type) and to in r.__bases__ and 'gevent.' not in r.__module__:
|
||||
subclass_modules.add(r)
|
||||
|
||||
return direct_ref_modules, subclass_modules
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_ssl(_warnings=None, _first_time=True):
|
||||
"""
|
||||
patch_ssl() -> None
|
||||
|
||||
Replace :class:`ssl.SSLSocket` object and socket wrapping functions in
|
||||
:mod:`ssl` with cooperative versions.
|
||||
|
||||
This is only useful if :func:`patch_socket` has been called.
|
||||
"""
|
||||
may_need_warning = (
|
||||
_first_time
|
||||
and 'ssl' in sys.modules
|
||||
and hasattr(sys.modules['ssl'], 'SSLContext'))
|
||||
# Previously, we didn't warn on Python 2 if pkg_resources has been imported
|
||||
# because that imports ssl and it's commonly used for namespace packages,
|
||||
# which typically means we're still in some early part of the import cycle.
|
||||
# However, with our new more discriminating check, that no longer seems to be a problem.
|
||||
# Prior to 3.6, we don't have the RecursionError problem, and prior to 3.7 we don't have the
|
||||
# SSLContext.sslsocket_class/SSLContext.sslobject_class problem.
|
||||
|
||||
gevent_mod, _ = _patch_module('ssl', _warnings=_warnings)
|
||||
if may_need_warning:
|
||||
direct_ref_modules, subclass_modules = _find_module_refs(
|
||||
gevent_mod.orig_SSLContext,
|
||||
excluding_names=('ssl', 'gevent.ssl', 'gevent._ssl3', 'gevent._sslgte279'))
|
||||
if direct_ref_modules or subclass_modules:
|
||||
# Normally you don't want to have dynamic warning strings, because
|
||||
# the cache in the warning module is based on the string. But we
|
||||
# specifically only do this the first time we patch ourself, so it's
|
||||
# ok.
|
||||
direct_ref_mod_str = subclass_str = ''
|
||||
if direct_ref_modules:
|
||||
direct_ref_mod_str = 'Modules that had direct imports (NOT patched): %s. ' % ([
|
||||
"%s (%s)" % (name, fname)
|
||||
for name, fname in direct_ref_modules
|
||||
])
|
||||
if subclass_modules:
|
||||
subclass_str = 'Subclasses (NOT patched): %s. ' % ([
|
||||
str(t) for t in subclass_modules
|
||||
])
|
||||
_queue_warning(
|
||||
'Monkey-patching ssl after ssl has already been imported '
|
||||
'may lead to errors, including RecursionError on Python 3.6. '
|
||||
'It may also silently lead to incorrect behaviour on Python 3.7. '
|
||||
'Please monkey-patch earlier. '
|
||||
'See https://github.com/gevent/gevent/issues/1016. '
|
||||
+ direct_ref_mod_str + subclass_str,
|
||||
_warnings)
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_select(aggressive=True):
|
||||
"""
|
||||
Replace :func:`select.select` with :func:`gevent.select.select`
|
||||
and :func:`select.poll` with :class:`gevent.select.poll` (where available).
|
||||
|
||||
If ``aggressive`` is true (the default), also remove other
|
||||
blocking functions from :mod:`select` .
|
||||
|
||||
- :func:`select.epoll`
|
||||
- :func:`select.kqueue`
|
||||
- :func:`select.kevent`
|
||||
- :func:`select.devpoll` (Python 3.5+)
|
||||
"""
|
||||
_patch_module('select',
|
||||
_patch_kwargs={'aggressive': aggressive})
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_selectors(aggressive=True):
|
||||
"""
|
||||
Replace :class:`selectors.DefaultSelector` with
|
||||
:class:`gevent.selectors.GeventSelector`.
|
||||
|
||||
If ``aggressive`` is true (the default), also remove other
|
||||
blocking classes :mod:`selectors`:
|
||||
|
||||
- :class:`selectors.EpollSelector`
|
||||
- :class:`selectors.KqueueSelector`
|
||||
- :class:`selectors.DevpollSelector` (Python 3.5+)
|
||||
|
||||
On Python 2, the :mod:`selectors2` module is used instead
|
||||
of :mod:`selectors` if it is available. If this module cannot
|
||||
be imported, no patching is done and :mod:`gevent.selectors` is
|
||||
not available.
|
||||
|
||||
In :func:`patch_all`, the *select* argument controls both this function
|
||||
and :func:`patch_select`.
|
||||
|
||||
.. versionadded:: 20.6.0
|
||||
"""
|
||||
try:
|
||||
_check_availability('selectors')
|
||||
except ImportError: # pragma: no cover
|
||||
return
|
||||
|
||||
_patch_module('selectors',
|
||||
_patch_kwargs={'aggressive': aggressive})
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_subprocess():
|
||||
"""
|
||||
Replace :func:`subprocess.call`, :func:`subprocess.check_call`,
|
||||
:func:`subprocess.check_output` and :class:`subprocess.Popen` with
|
||||
:mod:`cooperative versions <gevent.subprocess>`.
|
||||
|
||||
.. note::
|
||||
On Windows under Python 3, the API support may not completely match
|
||||
the standard library.
|
||||
|
||||
"""
|
||||
_patch_module('subprocess')
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_builtins():
|
||||
"""
|
||||
Make the builtin :func:`__import__` function `greenlet safe`_ under Python 2.
|
||||
|
||||
.. note::
|
||||
This does nothing under Python 3 as it is not necessary. Python 3 features
|
||||
improved import locks that are per-module, not global.
|
||||
|
||||
.. _greenlet safe: https://github.com/gevent/gevent/issues/108
|
||||
|
||||
.. deprecated:: 23.7.0
|
||||
Does nothing on any supported platform.
|
||||
"""
|
||||
|
||||
|
||||
@_ignores_DoNotPatch
|
||||
def patch_signal():
|
||||
"""
|
||||
Make the :func:`signal.signal` function work with a :func:`monkey-patched os <patch_os>`.
|
||||
|
||||
.. caution:: This method must be used with :func:`patch_os` to have proper ``SIGCHLD``
|
||||
handling. :func:`patch_all` calls both by default.
|
||||
|
||||
.. caution:: For proper ``SIGCHLD`` handling, you must yield to the event loop.
|
||||
Using :func:`patch_all` is the easiest way to ensure this.
|
||||
|
||||
.. seealso:: :mod:`gevent.signal`
|
||||
"""
|
||||
_patch_module("signal")
|
||||
|
||||
|
||||
def _check_repatching(**module_settings):
|
||||
_warnings = []
|
||||
key = '_gevent_saved_patch_all_module_settings'
|
||||
|
||||
del module_settings['kwargs']
|
||||
currently_patched = saved.setdefault(key, {})
|
||||
first_time = not currently_patched
|
||||
if not first_time and currently_patched != module_settings:
|
||||
_queue_warning("Patching more than once will result in the union of all True"
|
||||
" parameters being patched",
|
||||
_warnings)
|
||||
|
||||
to_patch = {}
|
||||
for k, v in module_settings.items():
|
||||
# If we haven't seen the setting at all, record it and echo it.
|
||||
# If we have seen the setting, but it became true, record it and echo it.
|
||||
if k not in currently_patched:
|
||||
to_patch[k] = currently_patched[k] = v
|
||||
elif v and not currently_patched[k]:
|
||||
to_patch[k] = currently_patched[k] = True
|
||||
|
||||
return _warnings, first_time, to_patch
|
||||
|
||||
|
||||
def _subscribe_signal_os(will_patch_all):
|
||||
if will_patch_all.will_patch_module('signal') and not will_patch_all.will_patch_module('os'):
|
||||
warnings = will_patch_all._warnings # Internal
|
||||
_queue_warning('Patching signal but not os will result in SIGCHLD handlers'
|
||||
' installed after this not being called and os.waitpid may not'
|
||||
' function correctly if gevent.subprocess is used. This may raise an'
|
||||
' error in the future.',
|
||||
warnings)
|
||||
|
||||
def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True,
|
||||
subprocess=True, sys=False, aggressive=True, Event=True,
|
||||
builtins=True, signal=True,
|
||||
queue=True, contextvars=True,
|
||||
**kwargs):
|
||||
"""
|
||||
Do all of the default monkey patching (calls every other applicable
|
||||
function in this module).
|
||||
|
||||
:return: A true value if patching all modules wasn't cancelled, a false
|
||||
value if it was.
|
||||
|
||||
.. versionchanged:: 1.1
|
||||
Issue a :mod:`warning <warnings>` if this function is called multiple times
|
||||
with different arguments. The second and subsequent calls will only add more
|
||||
patches, they can never remove existing patches by setting an argument to ``False``.
|
||||
.. versionchanged:: 1.1
|
||||
Issue a :mod:`warning <warnings>` if this function is called with ``os=False``
|
||||
and ``signal=True``. This will cause SIGCHLD handlers to not be called. This may
|
||||
be an error in the future.
|
||||
.. versionchanged:: 1.3a2
|
||||
``Event`` defaults to True.
|
||||
.. versionchanged:: 1.3b1
|
||||
Defined the return values.
|
||||
.. versionchanged:: 1.3b1
|
||||
Add ``**kwargs`` for the benefit of event subscribers. CAUTION: gevent may add
|
||||
and interpret additional arguments in the future, so it is suggested to use prefixes
|
||||
for kwarg values to be interpreted by plugins, for example, `patch_all(mylib_futures=True)`.
|
||||
.. versionchanged:: 1.3.5
|
||||
Add *queue*, defaulting to True, for Python 3.7.
|
||||
.. versionchanged:: 1.5
|
||||
Remove the ``httplib`` argument. Previously, setting it raised a ``ValueError``.
|
||||
.. versionchanged:: 1.5a3
|
||||
Add the ``contextvars`` argument.
|
||||
.. versionchanged:: 1.5
|
||||
Better handling of patching more than once.
|
||||
"""
|
||||
# pylint:disable=too-many-locals,too-many-branches
|
||||
|
||||
# Check to see if they're changing the patched list
|
||||
_warnings, first_time, modules_to_patch = _check_repatching(**locals())
|
||||
|
||||
if not modules_to_patch:
|
||||
# Nothing to do. Either the arguments were identical to what
|
||||
# we previously did, or they specified false values
|
||||
# for things we had previously patched.
|
||||
_process_warnings(_warnings)
|
||||
return
|
||||
|
||||
for k, v in modules_to_patch.items():
|
||||
locals()[k] = v
|
||||
|
||||
from gevent import events
|
||||
try:
|
||||
_notify_patch(events.GeventWillPatchAllEvent(modules_to_patch, kwargs), _warnings)
|
||||
except events.DoNotPatch:
|
||||
return False
|
||||
|
||||
# order is important
|
||||
if os:
|
||||
patch_os()
|
||||
if thread:
|
||||
patch_thread(Event=Event, _warnings=_warnings)
|
||||
if time:
|
||||
# time must be patched after thread, some modules used by thread
|
||||
# need access to the real time.sleep function.
|
||||
patch_time()
|
||||
|
||||
# sys must be patched after thread. in other cases threading._shutdown will be
|
||||
# initiated to _MainThread with real thread ident
|
||||
if sys:
|
||||
patch_sys()
|
||||
if socket:
|
||||
patch_socket(dns=dns, aggressive=aggressive)
|
||||
if select:
|
||||
patch_select(aggressive=aggressive)
|
||||
patch_selectors(aggressive=aggressive)
|
||||
if ssl:
|
||||
patch_ssl(_warnings=_warnings, _first_time=first_time)
|
||||
if subprocess:
|
||||
patch_subprocess()
|
||||
if builtins:
|
||||
patch_builtins()
|
||||
if signal:
|
||||
patch_signal()
|
||||
if queue:
|
||||
patch_queue()
|
||||
if contextvars:
|
||||
patch_contextvars()
|
||||
|
||||
_notify_patch(events.GeventDidPatchBuiltinModulesEvent(modules_to_patch, kwargs), _warnings)
|
||||
_notify_patch(events.GeventDidPatchAllEvent(modules_to_patch, kwargs), _warnings)
|
||||
|
||||
_process_warnings(_warnings)
|
||||
return True
|
||||
|
||||
def __getattr__(name):
|
||||
if name == 'main':
|
||||
from ._main import main
|
||||
return main
|
||||
raise AttributeError(name)
|
||||
2
venv3_12/Lib/site-packages/gevent/monkey/__main__.py
Normal file
2
venv3_12/Lib/site-packages/gevent/monkey/__main__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from ._main import main
|
||||
main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26
venv3_12/Lib/site-packages/gevent/monkey/_errors.py
Normal file
26
venv3_12/Lib/site-packages/gevent/monkey/_errors.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Exception classes and errors that this package may raise.
|
||||
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class _BadImplements(AttributeError):
|
||||
"""
|
||||
Raised when ``__implements__`` is incorrect.
|
||||
"""
|
||||
|
||||
def __init__(self, module):
|
||||
AttributeError.__init__(
|
||||
self,
|
||||
"Module %r has a bad or missing value for __implements__" % (module,)
|
||||
)
|
||||
|
||||
class MonkeyPatchWarning(RuntimeWarning):
|
||||
"""
|
||||
The type of warnings we issue.
|
||||
|
||||
.. versionadded:: 1.3a2
|
||||
"""
|
||||
117
venv3_12/Lib/site-packages/gevent/monkey/_main.py
Normal file
117
venv3_12/Lib/site-packages/gevent/monkey/_main.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
The real functionality to run this package as a main module.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def main():
|
||||
# TODO: Now that this is its own module, see if
|
||||
# we can refactor.
|
||||
# pylint:disable=too-many-locals
|
||||
import sys
|
||||
from . import patch_all
|
||||
|
||||
args = {}
|
||||
argv = sys.argv[1:]
|
||||
verbose = False
|
||||
run_fn = "run_path"
|
||||
script_help, patch_all_args, modules = _get_script_help()
|
||||
while argv and argv[0].startswith('--'):
|
||||
option = argv[0][2:]
|
||||
if option == 'verbose':
|
||||
verbose += 1
|
||||
elif option == 'module':
|
||||
run_fn = "run_module"
|
||||
elif option.startswith('no-') and option.replace('no-', '') in patch_all_args:
|
||||
args[option[3:]] = False
|
||||
elif option in patch_all_args:
|
||||
args[option] = True
|
||||
if option in modules:
|
||||
for module in modules:
|
||||
args.setdefault(module, False)
|
||||
else:
|
||||
sys.exit(script_help + '\n\n' + 'Cannot patch %r' % option)
|
||||
del argv[0]
|
||||
# TODO: break on --
|
||||
if verbose:
|
||||
import pprint
|
||||
import os
|
||||
print('gevent.monkey.patch_all(%s)' % ', '.join('%s=%s' % item for item in args.items()))
|
||||
print('sys.version=%s' % (sys.version.strip().replace('\n', ' '), ))
|
||||
print('sys.path=%s' % pprint.pformat(sys.path))
|
||||
print('sys.modules=%s' % pprint.pformat(sorted(sys.modules.keys())))
|
||||
print('cwd=%s' % os.getcwd())
|
||||
|
||||
if not argv:
|
||||
print(script_help)
|
||||
return
|
||||
|
||||
sys.argv[:] = argv
|
||||
# Make sure that we don't get imported again under a different
|
||||
# name (usually it's ``__main__`` here) because that could lead to
|
||||
# double-patching, and making monkey.get_original() not work.
|
||||
try:
|
||||
mod_name = __spec__.name
|
||||
except NameError:
|
||||
# Py2: __spec__ is not defined as standard
|
||||
mod_name = 'gevent.monkey'
|
||||
sys.modules[mod_name] = sys.modules[__name__]
|
||||
# On Python 2, we have to set the gevent.monkey attribute
|
||||
# manually; putting gevent.monkey into sys.modules stops the
|
||||
# import machinery from making that connection, and ``from gevent
|
||||
# import monkey`` is broken. On Python 3 (.8 at least) that's not
|
||||
# necessary.
|
||||
assert 'gevent.monkey' in sys.modules
|
||||
|
||||
# Running ``patch_all()`` will load pkg_resources entry point plugins
|
||||
# which may attempt to import ``gevent.monkey``, so it is critical that
|
||||
# we have established the correct saved module name first.
|
||||
patch_all(**args)
|
||||
|
||||
import runpy
|
||||
# Use runpy.run_path to closely (exactly) match what the
|
||||
# interpreter does given 'python <path>'. This includes allowing
|
||||
# passing .pyc/.pyo files and packages with a __main__ and
|
||||
# potentially even zip files. Previously we used exec, which only
|
||||
# worked if we directly read a python source file.
|
||||
run_meth = getattr(runpy, run_fn)
|
||||
return run_meth(sys.argv[0], run_name='__main__')
|
||||
|
||||
|
||||
def _get_script_help():
|
||||
# pylint:disable=deprecated-method
|
||||
import inspect
|
||||
from . import patch_all
|
||||
getter = inspect.getfullargspec
|
||||
|
||||
patch_all_args = getter(patch_all)[0]
|
||||
modules = [x for x in patch_all_args if 'patch_' + x in globals()]
|
||||
script_help = """gevent.monkey - monkey patch the standard modules to use gevent.
|
||||
|
||||
USAGE: ``python -m gevent.monkey [MONKEY OPTIONS] [--module] (script|module) [SCRIPT OPTIONS]``
|
||||
|
||||
If no MONKEY OPTIONS are present, monkey patches all the modules as if by calling ``patch_all()``.
|
||||
You can exclude a module with --no-<module>, e.g. --no-thread. You can
|
||||
specify a module to patch with --<module>, e.g. --socket. In the latter
|
||||
case only the modules specified on the command line will be patched.
|
||||
|
||||
The default behavior is to execute the script passed as argument. If you wish
|
||||
to run a module instead, pass the `--module` argument before the module name.
|
||||
|
||||
.. versionchanged:: 1.3b1
|
||||
The *script* argument can now be any argument that can be passed to `runpy.run_path`,
|
||||
just like the interpreter itself does, for example a package directory containing ``__main__.py``.
|
||||
Previously it had to be the path to
|
||||
a .py source file.
|
||||
|
||||
.. versionchanged:: 1.5
|
||||
The `--module` option has been added.
|
||||
|
||||
MONKEY OPTIONS: ``--verbose %s``""" % ', '.join('--[no-]%s' % m for m in modules)
|
||||
return script_help, patch_all_args, modules
|
||||
|
||||
main.__doc__ = _get_script_help()[0]
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
311
venv3_12/Lib/site-packages/gevent/monkey/_patch_thread_common.py
Normal file
311
venv3_12/Lib/site-packages/gevent/monkey/_patch_thread_common.py
Normal file
@@ -0,0 +1,311 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
The implementation of thread patching for Python versions
|
||||
prior to 3.13.
|
||||
|
||||
Internal use only.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from ._util import _patch_module
|
||||
from ._util import _queue_warning
|
||||
from ._util import _notify_patch
|
||||
|
||||
from ._state import is_object_patched
|
||||
|
||||
def _patch_existing_locks(threading):
|
||||
if len(list(threading.enumerate())) != 1:
|
||||
return
|
||||
# This is used to protect internal data structures for enumerate.
|
||||
# It's acquired when threads are started and when they're stopped.
|
||||
# Stopping a thread checks a Condition, which on Python 2 wants to test
|
||||
# _is_owned of its (patched) Lock. Since our LockType doesn't have
|
||||
# _is_owned, it tries to acquire the lock non-blocking; that triggers a
|
||||
# switch. If the next thing in the callback list was a thread that needed
|
||||
# to start or end, we wouldn't be able to acquire this native lock
|
||||
# because it was being held already; we couldn't switch either, so we'd
|
||||
# block permanently.
|
||||
threading._active_limbo_lock = threading._allocate_lock()
|
||||
try:
|
||||
tid = threading.get_ident()
|
||||
except AttributeError:
|
||||
tid = threading._get_ident()
|
||||
rlock_type = type(threading.RLock())
|
||||
try:
|
||||
import importlib._bootstrap
|
||||
except ImportError:
|
||||
class _ModuleLock(object):
|
||||
pass
|
||||
else:
|
||||
_ModuleLock = importlib._bootstrap._ModuleLock # python 2 pylint: disable=no-member
|
||||
# It might be possible to walk up all the existing stack frames to find
|
||||
# locked objects...at least if they use `with`. To be sure, we look at every object
|
||||
# Since we're supposed to be done very early in the process, there shouldn't be
|
||||
# too many.
|
||||
|
||||
# Note that the C implementation of locks, at least on some
|
||||
# versions of CPython, cannot be found and cannot be fixed (they simply
|
||||
# don't show up to GC; see https://github.com/gevent/gevent/issues/1354)
|
||||
|
||||
# By definition there's only one thread running, so the various
|
||||
# owner attributes were the old (native) thread id. Make it our
|
||||
# current greenlet id so that when it wants to unlock and compare
|
||||
# self.__owner with _get_ident(), they match.
|
||||
gc = __import__('gc')
|
||||
for o in gc.get_objects():
|
||||
if isinstance(o, rlock_type):
|
||||
for owner_name in (
|
||||
'_owner', # Python 3 or backported PyPy2
|
||||
'_RLock__owner', # Python 2
|
||||
):
|
||||
if hasattr(o, owner_name):
|
||||
if getattr(o, owner_name) is not None:
|
||||
setattr(o, owner_name, tid)
|
||||
break
|
||||
else: # pragma: no cover
|
||||
raise AssertionError(
|
||||
"Unsupported Python implementation; "
|
||||
"Found unknown lock implementation.",
|
||||
vars(o)
|
||||
)
|
||||
elif isinstance(o, _ModuleLock):
|
||||
if o.owner is not None:
|
||||
o.owner = tid
|
||||
|
||||
|
||||
|
||||
class BasePatcher:
|
||||
# Description of the hang:
|
||||
# There is an incompatibility with patching 'thread' and the 'multiprocessing' module:
|
||||
# The problem is that multiprocessing.queues.Queue uses a half-duplex multiprocessing.Pipe,
|
||||
# which is implemented with os.pipe() and _multiprocessing.Connection. os.pipe isn't patched
|
||||
# by gevent, as it returns just a fileno. _multiprocessing.Connection is an internal implementation
|
||||
# class implemented in C, which exposes a 'poll(timeout)' method; under the covers, this issues a
|
||||
# (blocking) select() call: hence the need for a real thread. Except for that method, we could
|
||||
# almost replace Connection with gevent.fileobject.SocketAdapter, plus a trivial
|
||||
# patch to os.pipe (below). Sigh, so close. (With a little work, we could replicate that method)
|
||||
|
||||
# import os
|
||||
# import fcntl
|
||||
# os_pipe = os.pipe
|
||||
# def _pipe():
|
||||
# r, w = os_pipe()
|
||||
# fcntl.fcntl(r, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
# fcntl.fcntl(w, fcntl.F_SETFL, os.O_NONBLOCK)
|
||||
# return r, w
|
||||
# os.pipe = _pipe
|
||||
|
||||
gevent_threading_mod = None
|
||||
gevent_thread_mod = None
|
||||
|
||||
thread_mod = None
|
||||
threading_mod = None
|
||||
orig_current_thread = None
|
||||
main_thread = None
|
||||
orig_shutdown = None
|
||||
|
||||
def __init__(self, threading=True, _threading_local=True, Event=True, logging=True,
|
||||
existing_locks=True,
|
||||
_warnings=None):
|
||||
self.threading = threading
|
||||
self.threading_local = _threading_local
|
||||
self.Event = Event
|
||||
self.logging = logging
|
||||
self.existing_locks = existing_locks
|
||||
self.warnings = _warnings
|
||||
|
||||
|
||||
|
||||
def __call__(self):
|
||||
# The 'threading' module copies some attributes from the
|
||||
# thread module the first time it is imported. If we patch 'thread'
|
||||
# before that happens, then we store the wrong values in 'saved',
|
||||
# So if we're going to patch threading, we either need to import it
|
||||
# before we patch thread, or manually clean up the attributes that
|
||||
# are in trouble. The latter is tricky because of the different names
|
||||
# on different versions.
|
||||
|
||||
|
||||
self.threading_mod = __import__('threading')
|
||||
# Capture the *real* current thread object before
|
||||
# we start returning DummyThread objects, for comparison
|
||||
# to the main thread.
|
||||
self.orig_current_thread = self.threading_mod.current_thread()
|
||||
self.main_thread = self.threading_mod.main_thread()
|
||||
self.orig_shutdown = self.threading_mod._shutdown
|
||||
|
||||
gevent_thread_mod, thread_mod = _patch_module('thread',
|
||||
_warnings=self.warnings,
|
||||
_notify_did_subscribers=False)
|
||||
|
||||
|
||||
if self.threading:
|
||||
self.patch_threading_event_logging_existing_locks()
|
||||
|
||||
if self.threading_local:
|
||||
self.patch__threading_local()
|
||||
|
||||
if self.threading:
|
||||
self.patch_active_threads()
|
||||
|
||||
|
||||
# Issue 18808 changes the nature of Thread.join() to use
|
||||
# locks. This means that a greenlet spawned in the main thread
|
||||
# (which is already running) cannot wait for the main thread---it
|
||||
# hangs forever. We patch around this if possible. See also
|
||||
# gevent.threading.
|
||||
already_patched = is_object_patched('threading', '_shutdown')
|
||||
|
||||
if self.orig_current_thread == self.threading_mod.main_thread() and not already_patched:
|
||||
self.patch_threading_shutdown_on_main_thread_not_already_patched()
|
||||
self.patch_main_thread_cleanup()
|
||||
|
||||
elif not already_patched:
|
||||
self.patch_shutdown_not_on_main_thread()
|
||||
|
||||
from gevent import events
|
||||
_notify_patch(events.GeventDidPatchModuleEvent('thread',
|
||||
gevent_thread_mod,
|
||||
thread_mod))
|
||||
if self.gevent_threading_mod is not None:
|
||||
_notify_patch(events.GeventDidPatchModuleEvent('threading',
|
||||
self.gevent_threading_mod,
|
||||
self.threading_mod))
|
||||
|
||||
def patch_threading_event_logging_existing_locks(self):
|
||||
|
||||
self.gevent_threading_mod, patched_mod = _patch_module(
|
||||
'threading',
|
||||
_warnings=self.warnings,
|
||||
_notify_did_subscribers=False)
|
||||
|
||||
assert patched_mod is self.threading_mod
|
||||
|
||||
if self.Event:
|
||||
self.patch_event()
|
||||
|
||||
if self.existing_locks:
|
||||
_patch_existing_locks(self.threading_mod)
|
||||
|
||||
if self.logging and 'logging' in sys.modules:
|
||||
self.patch_logging()
|
||||
|
||||
def patch_event(self):
|
||||
from .api import patch_item
|
||||
from gevent.event import Event
|
||||
patch_item(self.threading_mod, 'Event', Event)
|
||||
# Python 2 had `Event` as a function returning
|
||||
# the private class `_Event`. Some code may be relying
|
||||
# on that.
|
||||
if hasattr(self.threading_mod, '_Event'):
|
||||
patch_item(self.threading_mod, '_Event', Event)
|
||||
|
||||
def patch_logging(self):
|
||||
from .api import patch_item
|
||||
logging = __import__('logging')
|
||||
patch_item(logging, '_lock', self.threading_mod.RLock())
|
||||
for wr in logging._handlerList:
|
||||
# In py26, these are actual handlers, not weakrefs
|
||||
handler = wr() if callable(wr) else wr
|
||||
if handler is None:
|
||||
continue
|
||||
if not hasattr(handler, 'lock'):
|
||||
raise TypeError("Unknown/unsupported handler %r" % handler)
|
||||
handler.lock = self.threading_mod.RLock()
|
||||
|
||||
def patch__threading_local(self):
|
||||
_threading_local = __import__('_threading_local')
|
||||
from .api import patch_item
|
||||
from gevent.local import local
|
||||
patch_item(_threading_local, 'local', local)
|
||||
|
||||
def patch_active_threads(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def patch_threading_shutdown_on_main_thread_not_already_patched(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def patch_main_thread_cleanup(self):
|
||||
# We create a bit of a reference cycle here,
|
||||
# so main_thread doesn't get to be collected in a timely way.
|
||||
# Not good. Take it out of dangling so we don't get
|
||||
# warned about it.
|
||||
main_thread = self.main_thread
|
||||
self.threading_mod._dangling.remove(main_thread)
|
||||
|
||||
# Patch up the ident of the main thread to match. This
|
||||
# matters if threading was imported before monkey-patching
|
||||
# thread
|
||||
oldid = main_thread.ident
|
||||
main_thread._ident = self.threading_mod.get_ident()
|
||||
if oldid in self.threading_mod._active:
|
||||
self.threading_mod._active[main_thread.ident] = self.threading_mod._active[oldid]
|
||||
if oldid != main_thread.ident:
|
||||
del self.threading_mod._active[oldid]
|
||||
|
||||
def patch_shutdown_not_on_main_thread(self):
|
||||
_queue_warning("Monkey-patching not on the main thread; "
|
||||
"threading.main_thread().join() will hang from a greenlet",
|
||||
self.warnings)
|
||||
|
||||
from .api import patch_item
|
||||
|
||||
main_thread = self.main_thread
|
||||
threading_mod = self.threading_mod
|
||||
get_ident = self.threading_mod.get_ident
|
||||
orig_shutdown = self.orig_shutdown
|
||||
def _shutdown():
|
||||
# We've patched get_ident but *did not* patch the
|
||||
# main_thread.ident value. Beginning in Python 3.9.8
|
||||
# and then later releases (3.10.1, probably), the
|
||||
# _main_thread object is only _stop() if the ident of
|
||||
# the current thread (the *real* main thread) matches
|
||||
# the ident of the _main_thread object. But without doing that,
|
||||
# the main thread's shutdown lock (threading._shutdown_locks) is never
|
||||
# removed *or released*, thus hanging the interpreter.
|
||||
# XXX: There's probably a better way to do this. Probably need to take a
|
||||
# step back and look at the whole picture.
|
||||
main_thread._ident = get_ident()
|
||||
orig_shutdown()
|
||||
patch_item(threading_mod, '_shutdown', orig_shutdown)
|
||||
patch_item(threading_mod, '_shutdown', _shutdown)
|
||||
|
||||
@staticmethod # Static to be sure we don't accidentally capture `self` and keep it alive
|
||||
def _make_existing_non_main_thread_join_func(thread, thread_greenlet, threading_mod):
|
||||
from gevent.hub import sleep
|
||||
from time import time
|
||||
# TODO: This is almost the algorithm that the 3.13 _ThreadHandle class
|
||||
# employs. UNIFY them.
|
||||
def join(timeout=None):
|
||||
end = None
|
||||
if threading_mod.current_thread() is thread:
|
||||
raise RuntimeError("Cannot join current thread")
|
||||
if thread_greenlet is not None and thread_greenlet.dead:
|
||||
return
|
||||
# You may ask: Why not call thread_greenlet.join()?
|
||||
# Well, in the one case we actually have a greenlet, it's the
|
||||
# low-level greenlet.greenlet object for the main thread, which
|
||||
# doesn't have a join method.
|
||||
#
|
||||
# You may ask: Why not become the main greenlet's *parent*
|
||||
# so you can get notified when it finishes? Because you can't
|
||||
# create a greenlet cycle (the current greenlet is a descendent
|
||||
# of the parent), and nor can you set a greenlet's parent to None,
|
||||
# so there can only ever be one greenlet with a parent of None: the main
|
||||
# greenlet, the one we need to watch.
|
||||
#
|
||||
# You may ask: why not swizzle out the problematic lock on the main thread
|
||||
# into a gevent friendly lock? Well, the interpreter actually depends on that
|
||||
# for the main thread in threading._shutdown; see below.
|
||||
|
||||
if not thread.is_alive():
|
||||
return
|
||||
|
||||
if timeout:
|
||||
end = time() + timeout
|
||||
|
||||
while thread.is_alive():
|
||||
if end is not None and time() > end:
|
||||
return
|
||||
sleep(0.01)
|
||||
return join
|
||||
@@ -0,0 +1,91 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
The implementation of thread patching for Python versions
|
||||
after 3.13.
|
||||
|
||||
Internal use only.
|
||||
"""
|
||||
import sys
|
||||
|
||||
|
||||
from ._patch_thread_common import BasePatcher
|
||||
|
||||
class Patcher(BasePatcher):
|
||||
|
||||
|
||||
def patch_active_threads(self):
|
||||
from gevent.threading import main_native_thread
|
||||
|
||||
for thread in self.threading_mod._active.values():
|
||||
if thread == main_native_thread():
|
||||
from greenlet import getcurrent
|
||||
from gevent.thread import _ThreadHandle
|
||||
thread._after_fork = lambda new_ident=None: new_ident
|
||||
thread._handle = _ThreadHandle()
|
||||
thread._handle._set_greenlet(getcurrent())
|
||||
thread._ident = thread._handle.ident
|
||||
assert thread.ident == thread._handle.ident
|
||||
continue
|
||||
thread.join = self._make_existing_non_main_thread_join_func(thread,
|
||||
None,
|
||||
self.threading_mod)
|
||||
|
||||
def patch_threading_shutdown_on_main_thread_not_already_patched(self):
|
||||
import greenlet
|
||||
from .api import patch_item
|
||||
|
||||
main_thread = self.main_thread
|
||||
threading_mod = self.threading_mod
|
||||
orig_shutdown = self.orig_shutdown
|
||||
_greenlet = main_thread._greenlet = greenlet.getcurrent()
|
||||
|
||||
def _shutdown():
|
||||
# Release anyone trying to join() me,
|
||||
# and let us switch to them.
|
||||
main_thread._handle._set_done()
|
||||
from gevent import sleep
|
||||
try:
|
||||
sleep()
|
||||
except: # pylint:disable=bare-except
|
||||
# A greenlet could have .kill() us
|
||||
# or .throw() to us. I'm the main greenlet,
|
||||
# there's no where else for this to go.
|
||||
from gevent import get_hub
|
||||
get_hub().print_exception(_greenlet, *sys.exc_info())
|
||||
|
||||
# Now, this may have resulted in us getting stopped
|
||||
# if some other greenlet actually just ran there.
|
||||
# That's not good, we're not supposed to be stopped
|
||||
# when we enter _shutdown.
|
||||
class FakeHandle:
|
||||
def is_done(self):
|
||||
return False
|
||||
def _set_done(self):
|
||||
return
|
||||
def join(self):
|
||||
return
|
||||
main_thread._handle = FakeHandle()
|
||||
assert main_thread.is_alive()
|
||||
# main_thread._is_stopped = False
|
||||
# main_thread._tstate_lock = main_thread.__real_tstate_lock
|
||||
# main_thread.__real_tstate_lock = None
|
||||
# The only truly blocking native shutdown lock to
|
||||
# acquire should be our own (hopefully), and the call to
|
||||
# _stop that orig_shutdown makes will discard it.
|
||||
|
||||
# XXX: What if more get spawned?
|
||||
for t in list(threading_mod.enumerate()):
|
||||
if t.daemon or t is main_thread:
|
||||
continue
|
||||
while t.is_alive():
|
||||
try:
|
||||
t._handle.join(0.001)
|
||||
except RuntimeError:
|
||||
# Joining ourself.
|
||||
t._handle._set_done()
|
||||
break
|
||||
|
||||
orig_shutdown()
|
||||
patch_item(threading_mod, '_shutdown', self.orig_shutdown)
|
||||
|
||||
patch_item(self.threading_mod, '_shutdown', _shutdown)
|
||||
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
The implementation of thread patching for Python versions
|
||||
prior to 3.13.
|
||||
|
||||
Internal use only.
|
||||
"""
|
||||
import sys
|
||||
|
||||
|
||||
from ._patch_thread_common import BasePatcher
|
||||
|
||||
|
||||
class Patcher(BasePatcher):
|
||||
|
||||
def patch_active_threads(self):
|
||||
from gevent.threading import main_native_thread
|
||||
threading_mod = self.threading_mod
|
||||
for thread in threading_mod._active.values():
|
||||
if thread == main_native_thread():
|
||||
continue
|
||||
thread.join = self._make_existing_non_main_thread_join_func(thread, None, threading_mod)
|
||||
|
||||
|
||||
def patch_threading_shutdown_on_main_thread_not_already_patched(self):
|
||||
import greenlet
|
||||
from .api import patch_item
|
||||
threading_mod = self.threading_mod
|
||||
main_thread = self.main_thread
|
||||
orig_shutdown = self.orig_shutdown
|
||||
|
||||
_greenlet = main_thread._greenlet = greenlet.getcurrent()
|
||||
main_thread._gevent_real_tstate_lock = main_thread._tstate_lock
|
||||
assert main_thread._gevent_real_tstate_lock is not None
|
||||
# The interpreter will call threading._shutdown
|
||||
# when the main thread exits and is about to
|
||||
# go away. It is called *in* the main thread. This
|
||||
# is a perfect place to notify other greenlets that
|
||||
# the main thread is done. We do this by overriding the
|
||||
# lock of the main thread during operation, and only restoring
|
||||
# it to the native blocking version at shutdown time
|
||||
# (the interpreter also has a reference to this lock in a
|
||||
# C data structure).
|
||||
main_thread._tstate_lock = threading_mod.Lock()
|
||||
main_thread._tstate_lock.acquire()
|
||||
|
||||
def _shutdown():
|
||||
# Release anyone trying to join() me,
|
||||
# and let us switch to them.
|
||||
if not main_thread._tstate_lock:
|
||||
return
|
||||
|
||||
main_thread._tstate_lock.release()
|
||||
from gevent import sleep
|
||||
try:
|
||||
sleep()
|
||||
except: # pylint:disable=bare-except
|
||||
# A greenlet could have .kill() us
|
||||
# or .throw() to us. I'm the main greenlet,
|
||||
# there's no where else for this to go.
|
||||
from gevent import get_hub
|
||||
get_hub().print_exception(_greenlet, *sys.exc_info())
|
||||
|
||||
# Now, this may have resulted in us getting stopped
|
||||
# if some other greenlet actually just ran there.
|
||||
# That's not good, we're not supposed to be stopped
|
||||
# when we enter _shutdown.
|
||||
main_thread._is_stopped = False
|
||||
main_thread._tstate_lock = main_thread._gevent_real_tstate_lock
|
||||
main_thread._gevent_real_tstate_lock = None
|
||||
# The only truly blocking native shutdown lock to
|
||||
# acquire should be our own (hopefully), and the call to
|
||||
# _stop that orig_shutdown makes will discard it.
|
||||
|
||||
orig_shutdown()
|
||||
patch_item(threading_mod, '_shutdown', orig_shutdown)
|
||||
|
||||
patch_item(threading_mod, '_shutdown', _shutdown)
|
||||
70
venv3_12/Lib/site-packages/gevent/monkey/_state.py
Normal file
70
venv3_12/Lib/site-packages/gevent/monkey/_state.py
Normal file
@@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
State management and query functions for tracking and discovering what
|
||||
has been patched.
|
||||
"""
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# maps module name -> {attribute name: original item}
|
||||
# e.g. "time" -> {"sleep": built-in function sleep}
|
||||
# NOT A PUBLIC API. However, third-party monkey-patchers may be using
|
||||
# it? TODO: Provide better API for them.
|
||||
saved:dict = {}
|
||||
|
||||
|
||||
def is_module_patched(mod_name):
|
||||
"""
|
||||
Check if a module has been replaced with a cooperative version.
|
||||
|
||||
:param str mod_name: The name of the standard library module,
|
||||
e.g., ``'socket'``.
|
||||
|
||||
"""
|
||||
return mod_name in saved
|
||||
|
||||
|
||||
def is_object_patched(mod_name, item_name):
|
||||
"""
|
||||
Check if an object in a module has been replaced with a
|
||||
cooperative version.
|
||||
|
||||
:param str mod_name: The name of the standard library module,
|
||||
e.g., ``'socket'``.
|
||||
:param str item_name: The name of the attribute in the module,
|
||||
e.g., ``'create_connection'``.
|
||||
|
||||
"""
|
||||
return is_module_patched(mod_name) and item_name in saved[mod_name]
|
||||
|
||||
|
||||
def is_anything_patched():
|
||||
"""
|
||||
Check if this module has done any patching in the current process.
|
||||
This is currently only used in gevent tests.
|
||||
|
||||
Not currently a documented, public API, because I'm not convinced
|
||||
it is 100% reliable in the event of third-party patch functions that
|
||||
don't use ``saved``.
|
||||
|
||||
.. versionadded:: 21.1.0
|
||||
"""
|
||||
return bool(saved)
|
||||
|
||||
def _get_original(name, items):
|
||||
d = saved.get(name, {})
|
||||
values = []
|
||||
module = None
|
||||
for item in items:
|
||||
if item in d:
|
||||
values.append(d[item])
|
||||
else:
|
||||
if module is None:
|
||||
module = __import__(name)
|
||||
values.append(getattr(module, item))
|
||||
return values
|
||||
|
||||
def _save(module, attr_name, item):
|
||||
saved.setdefault(module.__name__, {}).setdefault(attr_name, item)
|
||||
105
venv3_12/Lib/site-packages/gevent/monkey/_util.py
Normal file
105
venv3_12/Lib/site-packages/gevent/monkey/_util.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Utilities used in patching.
|
||||
|
||||
Internal use only.
|
||||
|
||||
"""
|
||||
import sys
|
||||
|
||||
|
||||
def _notify_patch(event, _warnings=None):
|
||||
# Raises DoNotPatch if we're not supposed to patch
|
||||
from gevent.events import notify_and_call_entry_points
|
||||
|
||||
event._warnings = _warnings
|
||||
notify_and_call_entry_points(event)
|
||||
|
||||
def _ignores_DoNotPatch(func):
|
||||
|
||||
from functools import wraps
|
||||
|
||||
@wraps(func)
|
||||
def ignores(*args, **kwargs):
|
||||
from gevent.events import DoNotPatch
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except DoNotPatch:
|
||||
return False
|
||||
|
||||
return ignores
|
||||
|
||||
def _check_availability(name):
|
||||
"""
|
||||
Test that the source and target modules for *name* are
|
||||
available and return them.
|
||||
|
||||
:raise ImportError: If the source or target cannot be imported.
|
||||
:return: The tuple ``(gevent_module, target_module, target_module_name)``
|
||||
"""
|
||||
# Always import the gevent module first. This helps us be sure we can
|
||||
# use regular imports in gevent files (when we can't use gevent.monkey.get_original())
|
||||
gevent_module = getattr(__import__('gevent.' + name), name)
|
||||
target_module_name = getattr(gevent_module, '__target__', name)
|
||||
target_module = __import__(target_module_name)
|
||||
|
||||
return gevent_module, target_module, target_module_name
|
||||
|
||||
|
||||
def _patch_module(name,
|
||||
items=None,
|
||||
_warnings=None,
|
||||
_patch_kwargs=None,
|
||||
_notify_will_subscribers=True,
|
||||
_notify_did_subscribers=True,
|
||||
_call_hooks=True):
|
||||
|
||||
from .api import patch_module
|
||||
|
||||
gevent_module, target_module, target_module_name = _check_availability(name)
|
||||
|
||||
patch_module(target_module, gevent_module, items=items,
|
||||
_warnings=_warnings, _patch_kwargs=_patch_kwargs,
|
||||
_notify_will_subscribers=_notify_will_subscribers,
|
||||
_notify_did_subscribers=_notify_did_subscribers,
|
||||
_call_hooks=_call_hooks)
|
||||
|
||||
# On Python 2, the `futures` package will install
|
||||
# a bunch of modules with the same name as those from Python 3,
|
||||
# such as `_thread`; primarily these just do `from thread import *`,
|
||||
# meaning we have alternate references. If that's already been imported,
|
||||
# we need to attempt to patch that too.
|
||||
|
||||
# Be sure to keep the original states matching also.
|
||||
|
||||
alternate_names = getattr(gevent_module, '__alternate_targets__', ())
|
||||
from ._state import saved # TODO: Add apis for these use cases.
|
||||
for alternate_name in alternate_names:
|
||||
alternate_module = sys.modules.get(alternate_name)
|
||||
if alternate_module is not None and alternate_module is not target_module:
|
||||
saved.pop(alternate_name, None)
|
||||
patch_module(alternate_module, gevent_module, items=items,
|
||||
_warnings=_warnings,
|
||||
_notify_will_subscribers=False,
|
||||
_notify_did_subscribers=False,
|
||||
_call_hooks=False)
|
||||
saved[alternate_name] = saved[target_module_name]
|
||||
|
||||
return gevent_module, target_module
|
||||
|
||||
|
||||
def _queue_warning(message, _warnings):
|
||||
# Queues a warning to show after the monkey-patching process is all done.
|
||||
# Done this way to avoid extra imports during the process itself, just
|
||||
# in case. If we're calling a function one-off (unusual) go ahead and do it
|
||||
if _warnings is None:
|
||||
_process_warnings([message])
|
||||
else:
|
||||
_warnings.append(message)
|
||||
|
||||
|
||||
def _process_warnings(_warnings):
|
||||
import warnings
|
||||
from ._errors import MonkeyPatchWarning
|
||||
for warning in _warnings:
|
||||
warnings.warn(warning, MonkeyPatchWarning, stacklevel=3)
|
||||
199
venv3_12/Lib/site-packages/gevent/monkey/api.py
Normal file
199
venv3_12/Lib/site-packages/gevent/monkey/api.py
Normal file
@@ -0,0 +1,199 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Higher level functions that comprise parts of
|
||||
the public monkey patching API.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def get_original(mod_name, item_name):
|
||||
"""
|
||||
Retrieve the original object from a module.
|
||||
|
||||
If the object has not been patched, then that object will still be
|
||||
retrieved.
|
||||
|
||||
:param str|sequence mod_name: The name of the standard library module,
|
||||
e.g., ``'socket'``. Can also be a sequence of standard library
|
||||
modules giving alternate names to try, e.g., ``('thread', '_thread')``;
|
||||
the first importable module will supply all *item_name* items.
|
||||
:param str|sequence item_name: A string or sequence of strings naming the
|
||||
attribute(s) on the module ``mod_name`` to return.
|
||||
|
||||
:return: The original value if a string was given for
|
||||
``item_name`` or a sequence of original values if a
|
||||
sequence was passed.
|
||||
"""
|
||||
from ._state import _get_original
|
||||
|
||||
mod_names = [mod_name] if isinstance(mod_name, str) else mod_name
|
||||
if isinstance(item_name, str):
|
||||
item_names = [item_name]
|
||||
unpack = True
|
||||
else:
|
||||
item_names = item_name
|
||||
unpack = False
|
||||
|
||||
for mod in mod_names:
|
||||
try:
|
||||
result = _get_original(mod, item_names)
|
||||
except ImportError:
|
||||
if mod is mod_names[-1]:
|
||||
raise
|
||||
else:
|
||||
return result[0] if unpack else result
|
||||
|
||||
_NONE = object()
|
||||
|
||||
def patch_item(module, attr, newitem):
|
||||
from ._state import _save
|
||||
|
||||
olditem = getattr(module, attr, _NONE)
|
||||
if olditem is not _NONE:
|
||||
_save(module, attr, olditem)
|
||||
setattr(module, attr, newitem)
|
||||
|
||||
|
||||
def remove_item(module, attr):
|
||||
from ._state import _save
|
||||
|
||||
olditem = getattr(module, attr, _NONE)
|
||||
if olditem is _NONE:
|
||||
return
|
||||
_save(module, attr, olditem)
|
||||
|
||||
delattr(module, attr)
|
||||
|
||||
def patch_module(target_module, source_module, items=None,
|
||||
_warnings=None,
|
||||
_patch_kwargs=None,
|
||||
_notify_will_subscribers=True,
|
||||
_notify_did_subscribers=True,
|
||||
_call_hooks=True):
|
||||
"""
|
||||
patch_module(target_module, source_module, items=None)
|
||||
|
||||
Replace attributes in *target_module* with the attributes of the
|
||||
same name in *source_module*.
|
||||
|
||||
The *source_module* can provide some attributes to customize the process:
|
||||
|
||||
* ``__implements__`` is a list of attribute names to copy; if not present,
|
||||
the *items* keyword argument is mandatory. ``__implements__`` must only have
|
||||
names from the standard library module in it.
|
||||
* ``_gevent_will_monkey_patch(target_module, items, warn, **kwargs)``
|
||||
* ``_gevent_did_monkey_patch(target_module, items, warn, **kwargs)``
|
||||
These two functions in the *source_module* are called *if* they exist,
|
||||
before and after copying attributes, respectively. The "will" function
|
||||
may modify *items*. The value of *warn* is a function that should be called
|
||||
with a single string argument to issue a warning to the user. If the "will"
|
||||
function raises :exc:`gevent.events.DoNotPatch`, no patching will be done. These functions
|
||||
are called before any event subscribers or plugins.
|
||||
|
||||
:keyword list items: A list of attribute names to replace. If
|
||||
not given, this will be taken from the *source_module* ``__implements__``
|
||||
attribute.
|
||||
:return: A true value if patching was done, a false value if patching was canceled.
|
||||
|
||||
.. versionadded:: 1.3b1
|
||||
"""
|
||||
from gevent import events
|
||||
from ._errors import _BadImplements
|
||||
from ._util import _notify_patch
|
||||
|
||||
if items is None:
|
||||
try:
|
||||
items = source_module.__implements__
|
||||
except AttributeError as e:
|
||||
raise _BadImplements(source_module) from e
|
||||
|
||||
if items is None:
|
||||
raise _BadImplements(source_module)
|
||||
|
||||
try:
|
||||
if _call_hooks:
|
||||
__call_module_hook(source_module, 'will', target_module, items, _warnings)
|
||||
if _notify_will_subscribers:
|
||||
_notify_patch(
|
||||
events.GeventWillPatchModuleEvent(target_module.__name__, source_module,
|
||||
target_module, items),
|
||||
_warnings)
|
||||
except events.DoNotPatch:
|
||||
return False
|
||||
|
||||
# Undocumented, internal use: If the module defines
|
||||
# `_gevent_do_monkey_patch(patch_request: _GeventDoPatchRequest)` call that;
|
||||
# the module is responsible for its own patching.
|
||||
do_patch = getattr(
|
||||
source_module,
|
||||
'_gevent_do_monkey_patch',
|
||||
_GeventDoPatchRequest.default_patch_items
|
||||
)
|
||||
request = _GeventDoPatchRequest(target_module, source_module, items, _patch_kwargs)
|
||||
do_patch(request)
|
||||
|
||||
if _call_hooks:
|
||||
__call_module_hook(source_module, 'did', target_module, items, _warnings)
|
||||
|
||||
if _notify_did_subscribers:
|
||||
# We allow turning off the broadcast of the 'did' event for the benefit
|
||||
# of our internal functions which need to do additional work (besides copying
|
||||
# attributes) before their patch can be considered complete.
|
||||
_notify_patch(
|
||||
events.GeventDidPatchModuleEvent(target_module.__name__, source_module,
|
||||
target_module)
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
class _GeventDoPatchRequest(object):
|
||||
|
||||
get_original = staticmethod(get_original)
|
||||
|
||||
def __init__(self,
|
||||
target_module,
|
||||
source_module,
|
||||
items,
|
||||
patch_kwargs):
|
||||
self.target_module = target_module
|
||||
self.source_module = source_module
|
||||
self.items = items
|
||||
self.patch_kwargs = patch_kwargs or {}
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s target=%r source=%r items=%r kwargs=%r>' % (
|
||||
self.__class__.__name__,
|
||||
self.target_module,
|
||||
self.source_module,
|
||||
self.items,
|
||||
self.patch_kwargs
|
||||
)
|
||||
|
||||
def default_patch_items(self):
|
||||
for attr in self.items:
|
||||
patch_item(self.target_module, attr, getattr(self.source_module, attr))
|
||||
|
||||
def remove_item(self, target_module, *items):
|
||||
if isinstance(target_module, str):
|
||||
items = (target_module,) + items
|
||||
target_module = self.target_module
|
||||
|
||||
for item in items:
|
||||
remove_item(target_module, item)
|
||||
|
||||
def __call_module_hook(gevent_module, name, module, items, _warnings):
|
||||
# This function can raise DoNotPatch on 'will'
|
||||
|
||||
def warn(message):
|
||||
from ._util import _queue_warning
|
||||
_queue_warning(message, _warnings)
|
||||
|
||||
func_name = '_gevent_' + name + '_monkey_patch'
|
||||
try:
|
||||
func = getattr(gevent_module, func_name)
|
||||
except AttributeError:
|
||||
func = lambda *args: None
|
||||
|
||||
|
||||
func(module, items, warn)
|
||||
Reference in New Issue
Block a user