aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/events.py
diff options
context:
space:
mode:
authorJames Taylor <user234683@users.noreply.github.com>2018-09-14 19:32:27 -0700
committerJames Taylor <user234683@users.noreply.github.com>2018-09-14 19:32:27 -0700
commit4212164e91ba2f49583cf44ad623a29b36db8f77 (patch)
tree47aefe3c0162f03e0c823b43873356f69c1cd636 /python/gevent/events.py
parent6ca20ff7010f2bafc7fefcb8cad982be27a8aeae (diff)
downloadyt-local-4212164e91ba2f49583cf44ad623a29b36db8f77.tar.lz
yt-local-4212164e91ba2f49583cf44ad623a29b36db8f77.tar.xz
yt-local-4212164e91ba2f49583cf44ad623a29b36db8f77.zip
Windows: Use 32-bit distribution of python
Diffstat (limited to 'python/gevent/events.py')
-rw-r--r--python/gevent/events.py480
1 files changed, 480 insertions, 0 deletions
diff --git a/python/gevent/events.py b/python/gevent/events.py
new file mode 100644
index 0000000..12c02ec
--- /dev/null
+++ b/python/gevent/events.py
@@ -0,0 +1,480 @@
+# -*- coding: utf-8 -*-
+# Copyright 2018 gevent. See LICENSE for details.
+"""
+Publish/subscribe event infrastructure.
+
+When certain "interesting" things happen during the lifetime of the
+process, gevent will "publish" an event (an object). That event is
+delivered to interested "subscribers" (functions that take one
+parameter, the event object).
+
+Higher level frameworks may take this foundation and build richer
+models on it.
+
+If :mod:`zope.event` is installed, then it will be used to provide the
+functionality of `notify` and `subscribers`. See
+:mod:`zope.event.classhandler` for a simple class-based approach to
+subscribing to a filtered list of events, and see `zope.component
+<https://zopecomponent.readthedocs.io/en/latest/event.html>`_ for a
+much higher-level, flexible system. If you are using one of these systems,
+you generally will not want to directly modify `subscribers`.
+
+.. versionadded:: 1.3b1
+"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+
+__all__ = [
+ 'subscribers',
+
+ # monitor thread
+ 'IEventLoopBlocked',
+ 'EventLoopBlocked',
+ 'IMemoryUsageThresholdExceeded',
+ 'MemoryUsageThresholdExceeded',
+ 'IMemoryUsageUnderThreshold',
+ 'MemoryUsageUnderThreshold',
+
+ # Hub
+ 'IPeriodicMonitorThread',
+ 'IPeriodicMonitorThreadStartedEvent',
+ 'PeriodicMonitorThreadStartedEvent',
+
+ # monkey
+ 'IGeventPatchEvent',
+ 'GeventPatchEvent',
+ 'IGeventWillPatchEvent',
+ 'DoNotPatch',
+ 'GeventWillPatchEvent',
+ 'IGeventDidPatchEvent',
+ 'IGeventWillPatchModuleEvent',
+ 'GeventWillPatchModuleEvent',
+ 'IGeventDidPatchModuleEvent',
+ 'GeventDidPatchModuleEvent',
+ 'IGeventWillPatchAllEvent',
+ 'GeventWillPatchAllEvent',
+ 'IGeventDidPatchBuiltinModulesEvent',
+ 'GeventDidPatchBuiltinModulesEvent',
+ 'IGeventDidPatchAllEvent',
+ 'GeventDidPatchAllEvent',
+]
+
+# pylint:disable=no-self-argument
+
+try:
+ from zope.event import subscribers
+ from zope.event import notify
+except ImportError:
+ #: Applications may register for notification of events by appending a
+ #: callable to the ``subscribers`` list.
+ #:
+ #: Each subscriber takes a single argument, which is the event object
+ #: being published.
+ #:
+ #: Exceptions raised by subscribers will be propagated *without* running
+ #: any remaining subscribers.
+ subscribers = []
+
+ def notify(event):
+ """
+ Notify all subscribers of ``event``.
+ """
+ for subscriber in subscribers:
+ subscriber(event)
+
+notify = notify # export
+try:
+ # pkg_resources is technically optional, we don't
+ # list a hard dependency on it.
+ __import__('pkg_resources')
+except ImportError:
+ notify_and_call_entry_points = notify
+else:
+ from pkg_resources import iter_entry_points
+ import platform
+ try:
+ # Cache the platform info. pkg_resources uses
+ # platform.machine() for environment markers, and
+ # platform.machine() wants to call os.popen('uname'), which is
+ # broken on Py2 when the gevent child signal handler is
+ # installed. (see test__monkey_sigchild_2.py)
+ platform.uname()
+ except: # pylint:disable=bare-except
+ pass
+ finally:
+ del platform
+
+ def notify_and_call_entry_points(event):
+ notify(event)
+ for plugin in iter_entry_points(event.ENTRY_POINT_NAME):
+ subscriber = plugin.load()
+ subscriber(event)
+
+from gevent._util import Interface
+from gevent._util import implementer
+from gevent._util import Attribute
+
+
+class IPeriodicMonitorThread(Interface):
+ """
+ The contract for the periodic monitoring thread that is started
+ by the hub.
+ """
+
+ def add_monitoring_function(function, period):
+ """
+ Schedule the *function* to be called approximately every *period* fractional seconds.
+
+ The *function* receives one argument, the hub being monitored. It is called
+ in the monitoring thread, *not* the hub thread. It **must not** attempt to
+ use the gevent asynchronous API.
+
+ If the *function* is already a monitoring function, then its *period*
+ will be updated for future runs.
+
+ If the *period* is ``None``, then the function will be removed.
+
+ A *period* less than or equal to zero is not allowed.
+ """
+
+class IPeriodicMonitorThreadStartedEvent(Interface):
+ """
+ The event emitted when a hub starts a periodic monitoring thread.
+
+ You can use this event to add additional monitoring functions.
+ """
+
+ monitor = Attribute("The instance of `IPeriodicMonitorThread` that was started.")
+
+class PeriodicMonitorThreadStartedEvent(object):
+ """
+ The implementation of :class:`IPeriodicMonitorThreadStartedEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.hub.periodic_monitor_thread_started'
+
+ def __init__(self, monitor):
+ self.monitor = monitor
+
+class IEventLoopBlocked(Interface):
+ """
+ The event emitted when the event loop is blocked.
+
+ This event is emitted in the monitor thread.
+ """
+
+ greenlet = Attribute("The greenlet that appeared to be blocking the loop.")
+ blocking_time = Attribute("The approximate time in seconds the loop has been blocked.")
+ info = Attribute("A sequence of string lines providing extra info.")
+
+@implementer(IEventLoopBlocked)
+class EventLoopBlocked(object):
+ """
+ The event emitted when the event loop is blocked.
+
+ Implements `IEventLoopBlocked`.
+ """
+
+ def __init__(self, greenlet, blocking_time, info):
+ self.greenlet = greenlet
+ self.blocking_time = blocking_time
+ self.info = info
+
+class IMemoryUsageThresholdExceeded(Interface):
+ """
+ The event emitted when the memory usage threshold is exceeded.
+
+ This event is emitted only while memory continues to grow
+ above the threshold. Only if the condition or stabilized is corrected (memory
+ usage drops) will the event be emitted in the future.
+
+ This event is emitted in the monitor thread.
+ """
+
+ mem_usage = Attribute("The current process memory usage, in bytes.")
+ max_allowed = Attribute("The maximum allowed memory usage, in bytes.")
+ memory_info = Attribute("The tuple of memory usage stats return by psutil.")
+
+class _AbstractMemoryEvent(object):
+
+ def __init__(self, mem_usage, max_allowed, memory_info):
+ self.mem_usage = mem_usage
+ self.max_allowed = max_allowed
+ self.memory_info = memory_info
+
+ def __repr__(self):
+ return "<%s used=%d max=%d details=%r>" % (
+ self.__class__.__name__,
+ self.mem_usage,
+ self.max_allowed,
+ self.memory_info,
+ )
+
+@implementer(IMemoryUsageThresholdExceeded)
+class MemoryUsageThresholdExceeded(_AbstractMemoryEvent):
+ """
+ Implementation of `IMemoryUsageThresholdExceeded`.
+ """
+
+
+class IMemoryUsageUnderThreshold(Interface):
+ """
+ The event emitted when the memory usage drops below the
+ threshold after having previously been above it.
+
+ This event is emitted only the first time memory usage is detected
+ to be below the threshold after having previously been above it.
+ If memory usage climbs again, a `IMemoryUsageThresholdExceeded`
+ event will be broadcast, and then this event could be broadcast again.
+
+ This event is emitted in the monitor thread.
+ """
+
+ mem_usage = Attribute("The current process memory usage, in bytes.")
+ max_allowed = Attribute("The maximum allowed memory usage, in bytes.")
+ max_memory_usage = Attribute("The memory usage that caused the previous "
+ "IMemoryUsageThresholdExceeded event.")
+ memory_info = Attribute("The tuple of memory usage stats return by psutil.")
+
+
+@implementer(IMemoryUsageUnderThreshold)
+class MemoryUsageUnderThreshold(_AbstractMemoryEvent):
+ """
+ Implementation of `IMemoryUsageUnderThreshold`.
+ """
+
+ def __init__(self, mem_usage, max_allowed, memory_info, max_usage):
+ super(MemoryUsageUnderThreshold, self).__init__(mem_usage, max_allowed, memory_info)
+ self.max_memory_usage = max_usage
+
+
+class IGeventPatchEvent(Interface):
+ """
+ The root for all monkey-patch events gevent emits.
+ """
+
+ source = Attribute("The source object containing the patches.")
+ target = Attribute("The destination object to be patched.")
+
+@implementer(IGeventPatchEvent)
+class GeventPatchEvent(object):
+ """
+ Implementation of `IGeventPatchEvent`.
+ """
+
+ def __init__(self, source, target):
+ self.source = source
+ self.target = target
+
+ def __repr__(self):
+ return '<%s source=%r target=%r at %x>' % (self.__class__.__name__,
+ self.source,
+ self.target,
+ id(self))
+
+class IGeventWillPatchEvent(IGeventPatchEvent):
+ """
+ An event emitted *before* gevent monkey-patches something.
+
+ If a subscriber raises `DoNotPatch`, then patching this particular
+ item will not take place.
+ """
+
+
+class DoNotPatch(BaseException):
+ """
+ Subscribers to will-patch events can raise instances
+ of this class to tell gevent not to patch that particular item.
+ """
+
+
+@implementer(IGeventWillPatchEvent)
+class GeventWillPatchEvent(GeventPatchEvent):
+ """
+ Implementation of `IGeventWillPatchEvent`.
+ """
+
+class IGeventDidPatchEvent(IGeventPatchEvent):
+ """
+ An event emitted *after* gevent has patched something.
+ """
+
+@implementer(IGeventDidPatchEvent)
+class GeventDidPatchEvent(GeventPatchEvent):
+ """
+ Implementation of `IGeventDidPatchEvent`.
+ """
+
+class IGeventWillPatchModuleEvent(IGeventWillPatchEvent):
+ """
+ An event emitted *before* gevent begins patching a specific module.
+
+ Both *source* and *target* attributes are module objects.
+ """
+
+ module_name = Attribute("The name of the module being patched. "
+ "This is the same as ``target.__name__``.")
+
+ target_item_names = Attribute("The list of item names to patch. "
+ "This can be modified in place with caution.")
+
+@implementer(IGeventWillPatchModuleEvent)
+class GeventWillPatchModuleEvent(GeventWillPatchEvent):
+ """
+ Implementation of `IGeventWillPatchModuleEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.monkey.will_patch_module'
+
+ def __init__(self, module_name, source, target, items):
+ super(GeventWillPatchModuleEvent, self).__init__(source, target)
+ self.module_name = module_name
+ self.target_item_names = items
+
+
+class IGeventDidPatchModuleEvent(IGeventDidPatchEvent):
+ """
+ An event emitted *after* gevent has completed patching a specific
+ module.
+ """
+
+ module_name = Attribute("The name of the module being patched. "
+ "This is the same as ``target.__name__``.")
+
+
+@implementer(IGeventDidPatchModuleEvent)
+class GeventDidPatchModuleEvent(GeventDidPatchEvent):
+ """
+ Implementation of `IGeventDidPatchModuleEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_module'
+
+ def __init__(self, module_name, source, target):
+ super(GeventDidPatchModuleEvent, self).__init__(source, target)
+ self.module_name = module_name
+
+# TODO: Maybe it would be useful for the the module patch events
+# to have an attribute telling if they're being done during patch_all?
+
+class IGeventWillPatchAllEvent(IGeventWillPatchEvent):
+ """
+ An event emitted *before* gevent begins patching the system.
+
+ Following this event will be a series of
+ `IGeventWillPatchModuleEvent` and `IGeventDidPatchModuleEvent` for
+ each patched module.
+
+ Once the gevent builtin modules have been processed,
+ `IGeventDidPatchBuiltinModulesEvent` will be emitted. Processing
+ this event is an ideal time for third-party modules to be imported
+ and patched (which may trigger its own will/did patch module
+ events).
+
+ Finally, a `IGeventDidPatchAllEvent` will be sent.
+
+ If a subscriber to this event raises `DoNotPatch`, no patching
+ will be done.
+
+ The *source* and *target* attributes have undefined values.
+ """
+
+ patch_all_arguments = Attribute(
+ "A dictionary of all the arguments to `gevent.monkey.patch_all`. "
+ "This dictionary should not be modified. "
+ )
+
+ patch_all_kwargs = Attribute(
+ "A dictionary of the extra arguments to `gevent.monkey.patch_all`. "
+ "This dictionary should not be modified. "
+ )
+
+ def will_patch_module(module_name):
+ """
+ Return whether the module named *module_name* will be patched.
+ """
+
+class _PatchAllMixin(object):
+ def __init__(self, patch_all_arguments, patch_all_kwargs):
+ super(_PatchAllMixin, self).__init__(None, None)
+ self._patch_all_arguments = patch_all_arguments
+ self._patch_all_kwargs = patch_all_kwargs
+
+ @property
+ def patch_all_arguments(self):
+ return self._patch_all_arguments.copy()
+
+ @property
+ def patch_all_kwargs(self):
+ return self._patch_all_kwargs.copy()
+
+ def __repr__(self):
+ return '<%s %r at %x>' % (self.__class__.__name__,
+ self._patch_all_arguments,
+ id(self))
+
+@implementer(IGeventWillPatchAllEvent)
+class GeventWillPatchAllEvent(_PatchAllMixin, GeventWillPatchEvent):
+ """
+ Implementation of `IGeventWillPatchAllEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.monkey.will_patch_all'
+
+ def will_patch_module(self, module_name):
+ return self.patch_all_arguments.get(module_name)
+
+class IGeventDidPatchBuiltinModulesEvent(IGeventDidPatchEvent):
+ """
+ Event emitted *after* the builtin modules have been patched.
+
+ The values of the *source* and *target* attributes are undefined.
+ """
+
+ patch_all_arguments = Attribute(
+ "A dictionary of all the arguments to `gevent.monkey.patch_all`. "
+ "This dictionary should not be modified. "
+ )
+
+ patch_all_kwargs = Attribute(
+ "A dictionary of the extra arguments to `gevent.monkey.patch_all`. "
+ "This dictionary should not be modified. "
+ )
+
+@implementer(IGeventDidPatchBuiltinModulesEvent)
+class GeventDidPatchBuiltinModulesEvent(_PatchAllMixin, GeventDidPatchEvent):
+ """
+ Implementation of `IGeventDidPatchBuiltinModulesEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_builtins'
+
+class IGeventDidPatchAllEvent(IGeventDidPatchEvent):
+ """
+ Event emitted after gevent has patched all modules, both builtin
+ and those provided by plugins/subscribers.
+
+ The values of the *source* and *target* attributes are undefined.
+ """
+
+@implementer(IGeventDidPatchAllEvent)
+class GeventDidPatchAllEvent(_PatchAllMixin, GeventDidPatchEvent):
+ """
+ Implementation of `IGeventDidPatchAllEvent`.
+ """
+
+ #: The name of the setuptools entry point that is called when this
+ #: event is emitted.
+ ENTRY_POINT_NAME = 'gevent.plugins.monkey.did_patch_all'