aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/_config.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/gevent/_config.py')
-rw-r--r--python/gevent/_config.py709
1 files changed, 0 insertions, 709 deletions
diff --git a/python/gevent/_config.py b/python/gevent/_config.py
deleted file mode 100644
index aaf74e6..0000000
--- a/python/gevent/_config.py
+++ /dev/null
@@ -1,709 +0,0 @@
-# Copyright (c) 2018 gevent. See LICENSE for details.
-"""
-gevent tunables.
-
-This should be used as ``from gevent import config``. That variable
-is an object of :class:`Config`.
-
-.. versionadded:: 1.3a2
-"""
-
-from __future__ import print_function, absolute_import, division
-
-import importlib
-import os
-import sys
-import textwrap
-
-from gevent._compat import string_types
-from gevent._compat import WIN
-
-__all__ = [
- 'config',
-]
-
-ALL_SETTINGS = []
-
-class SettingType(type):
- # pylint:disable=bad-mcs-classmethod-argument
-
- def __new__(cls, name, bases, cls_dict):
- if name == 'Setting':
- return type.__new__(cls, name, bases, cls_dict)
-
- cls_dict["order"] = len(ALL_SETTINGS)
- if 'name' not in cls_dict:
- cls_dict['name'] = name.lower()
-
- if 'environment_key' not in cls_dict:
- cls_dict['environment_key'] = 'GEVENT_' + cls_dict['name'].upper()
-
-
- new_class = type.__new__(cls, name, bases, cls_dict)
- new_class.fmt_desc(cls_dict.get("desc", ""))
- new_class.__doc__ = new_class.desc
- ALL_SETTINGS.append(new_class)
-
- if new_class.document:
- setting_name = cls_dict['name']
-
- def getter(self):
- return self.settings[setting_name].get()
-
- def setter(self, value): # pragma: no cover
- # The setter should never be hit, Config has a
- # __setattr__ that would override. But for the sake
- # of consistency we provide one.
- self.settings[setting_name].set(value)
-
- prop = property(getter, setter, doc=new_class.__doc__)
-
- setattr(Config, cls_dict['name'], prop)
- return new_class
-
- def fmt_desc(cls, desc):
- desc = textwrap.dedent(desc).strip()
- if hasattr(cls, 'shortname_map'):
- desc += (
- "\n\nThis is an importable value. It can be "
- "given as a string naming an importable object, "
- "or a list of strings in preference order and the first "
- "successfully importable object will be used. (Separate values "
- "in the environment variable with commas.) "
- "It can also be given as the callable object itself (in code). "
- )
- if cls.shortname_map:
- desc += "Shorthand names for default objects are %r" % (list(cls.shortname_map),)
- if getattr(cls.validate, '__doc__'):
- desc += '\n\n' + textwrap.dedent(cls.validate.__doc__).strip()
- if isinstance(cls.default, str) and hasattr(cls, 'shortname_map'):
- default = "`%s`" % (cls.default,)
- else:
- default = "`%r`" % (cls.default,)
- desc += "\n\nThe default value is %s" % (default,)
- desc += ("\n\nThe environment variable ``%s`` "
- "can be used to control this." % (cls.environment_key,))
- setattr(cls, "desc", desc)
- return desc
-
-def validate_invalid(value):
- raise ValueError("Not a valid value: %r" % (value,))
-
-def validate_bool(value):
- """
- This is a boolean value.
-
- In the environment variable, it may be given as ``1``, ``true``,
- ``on`` or ``yes`` for `True`, or ``0``, ``false``, ``off``, or
- ``no`` for `False`.
- """
- if isinstance(value, string_types):
- value = value.lower().strip()
- if value in ('1', 'true', 'on', 'yes'):
- value = True
- elif value in ('0', 'false', 'off', 'no') or not value:
- value = False
- else:
- raise ValueError("Invalid boolean string: %r" % (value,))
- return bool(value)
-
-def validate_anything(value):
- return value
-
-convert_str_value_as_is = validate_anything
-
-class Setting(object):
- name = None
- value = None
- validate = staticmethod(validate_invalid)
- default = None
- environment_key = None
- document = True
-
- desc = """\
-
- A long ReST description.
-
- The first line should be a single sentence.
-
- """
-
- def _convert(self, value):
- if isinstance(value, string_types):
- return value.split(',')
- return value
-
- def _default(self):
- result = os.environ.get(self.environment_key, self.default)
- result = self._convert(result)
- return result
-
- def get(self):
- # If we've been specifically set, return it
- if 'value' in self.__dict__:
- return self.value
- # Otherwise, read from the environment and reify
- # so we return consistent results.
- self.value = self.validate(self._default())
- return self.value
-
- def set(self, val):
- self.value = self.validate(self._convert(val))
-
-
-Setting = SettingType('Setting', (Setting,), dict(Setting.__dict__))
-
-def make_settings():
- """
- Return fresh instances of all classes defined in `ALL_SETTINGS`.
- """
- settings = {}
- for setting_kind in ALL_SETTINGS:
- setting = setting_kind()
- assert setting.name not in settings
- settings[setting.name] = setting
- return settings
-
-
-class Config(object):
- """
- Global configuration for gevent.
-
- There is one instance of this object at ``gevent.config``. If you
- are going to make changes in code, instead of using the documented
- environment variables, you need to make the changes before using
- any parts of gevent that might need those settings. For example::
-
- >>> from gevent import config
- >>> config.fileobject = 'thread'
-
- >>> from gevent import fileobject
- >>> fileobject.FileObject.__name__
- 'FileObjectThread'
-
- .. versionadded:: 1.3a2
-
- """
-
- def __init__(self):
- self.settings = make_settings()
-
- def __getattr__(self, name):
- if name not in self.settings:
- raise AttributeError("No configuration setting for: %r" % name)
- return self.settings[name].get()
-
- def __setattr__(self, name, value):
- if name != "settings" and name in self.settings:
- self.set(name, value)
- else:
- super(Config, self).__setattr__(name, value)
-
- def set(self, name, value):
- if name not in self.settings:
- raise AttributeError("No configuration setting for: %r" % name)
- self.settings[name].set(value)
-
- def __dir__(self):
- return list(self.settings)
-
-
-class ImportableSetting(object):
-
- def _import(self, path, _NONE=object):
- # pylint:disable=too-many-branches
- if isinstance(path, list):
- if not path:
- raise ImportError('Cannot import from empty list: %r' % (path, ))
-
- for item in path[:-1]:
- try:
- return self._import(item)
- except ImportError:
- pass
-
- return self._import(path[-1])
-
- if not isinstance(path, string_types):
- return path
-
- if '.' not in path:
- raise ImportError("Cannot import %r. "
- "Required format: [path/][package.]module.class. "
- "Or choose from %r"
- % (path, list(self.shortname_map)))
-
- if '/' in path:
- # This is dangerous, subject to race conditions, and
- # may not work properly for things like namespace packages
- import warnings
- warnings.warn("Absolute paths are deprecated and will be removed in 1.4."
- "Please put the package on sys.path first",
- DeprecationWarning)
- package_path, path = path.rsplit('/', 1)
- sys.path = [package_path] + sys.path
- else:
- package_path = None
-
- try:
- module, item = path.rsplit('.', 1)
- module = importlib.import_module(module)
- x = getattr(module, item, _NONE)
- if x is _NONE:
- raise ImportError('Cannot import %r from %r' % (item, module))
- return x
- finally:
- if package_path:
- try:
- sys.path.remove(package_path)
- except ValueError: # pragma: no cover
- pass
-
- shortname_map = {}
-
- def validate(self, value):
- if isinstance(value, type):
- return value
- return self._import([self.shortname_map.get(x, x) for x in value])
-
-class BoolSettingMixin(object):
- validate = staticmethod(validate_bool)
- # Don't do string-to-list conversion.
- _convert = staticmethod(convert_str_value_as_is)
-
-class IntSettingMixin(object):
- # Don't do string-to-list conversion.
- def _convert(self, value):
- if value:
- return int(value)
-
- validate = staticmethod(validate_anything)
-
-
-class _PositiveValueMixin(object):
-
- def validate(self, value):
- if value is not None and value <= 0:
- raise ValueError("Must be positive")
- return value
-
-
-class FloatSettingMixin(_PositiveValueMixin):
- def _convert(self, value):
- if value:
- return float(value)
-
-
-class ByteCountSettingMixin(_PositiveValueMixin):
-
- _MULTIPLES = {
- # All keys must be the same size.
- 'kb': 1024,
- 'mb': 1024 * 1024,
- 'gb': 1024 * 1024 * 1024,
- }
-
- _SUFFIX_SIZE = 2
-
- def _convert(self, value):
- if not value or not isinstance(value, str):
- return value
- value = value.lower()
- for s, m in self._MULTIPLES.items():
- if value[-self._SUFFIX_SIZE:] == s:
- return int(value[:-self._SUFFIX_SIZE]) * m
- return int(value)
-
-
-class Resolver(ImportableSetting, Setting):
-
- desc = """\
- The callable that will be used to create
- :attr:`gevent.hub.Hub.resolver`.
-
- See :doc:`dns` for more information.
- """
-
- default = [
- 'thread',
- 'dnspython',
- 'ares',
- 'block',
- ]
-
- shortname_map = {
- 'ares': 'gevent.resolver.ares.Resolver',
- 'thread': 'gevent.resolver.thread.Resolver',
- 'block': 'gevent.resolver.blocking.Resolver',
- 'dnspython': 'gevent.resolver.dnspython.Resolver',
- }
-
-
-
-class Threadpool(ImportableSetting, Setting):
-
- desc = """\
- The kind of threadpool we use.
- """
-
- default = 'gevent.threadpool.ThreadPool'
-
-
-class Loop(ImportableSetting, Setting):
-
- desc = """\
- The kind of the loop we use.
-
- On Windows, this defaults to libuv, while on
- other platforms it defaults to libev.
-
- """
-
- default = [
- 'libev-cext',
- 'libev-cffi',
- 'libuv-cffi',
- ] if not WIN else [
- 'libuv-cffi',
- 'libev-cext',
- 'libev-cffi',
- ]
-
- shortname_map = {
- 'libev-cext': 'gevent.libev.corecext.loop',
- 'libev-cffi': 'gevent.libev.corecffi.loop',
- 'libuv-cffi': 'gevent.libuv.loop.loop',
- }
-
- shortname_map['libuv'] = shortname_map['libuv-cffi']
-
-
-class FormatContext(ImportableSetting, Setting):
- name = 'format_context'
-
- # using pprint.pformat can override custom __repr__ methods on dict/list
- # subclasses, which can be a security concern
- default = 'pprint.saferepr'
-
-
-class LibevBackend(Setting):
- name = 'libev_backend'
- environment_key = 'GEVENT_BACKEND'
-
- desc = """\
- The backend for libev, such as 'select'
- """
-
- default = None
-
- validate = staticmethod(validate_anything)
-
-
-class FileObject(ImportableSetting, Setting):
- desc = """\
- The kind of ``FileObject`` we will use.
-
- See :mod:`gevent.fileobject` for a detailed description.
-
- """
- environment_key = 'GEVENT_FILE'
-
- default = [
- 'posix',
- 'thread',
- ]
-
- shortname_map = {
- 'thread': 'gevent._fileobjectcommon.FileObjectThread',
- 'posix': 'gevent._fileobjectposix.FileObjectPosix',
- 'block': 'gevent._fileobjectcommon.FileObjectBlock'
- }
-
-
-class WatchChildren(BoolSettingMixin, Setting):
- desc = """\
- Should we *not* watch children with the event loop watchers?
-
- This is an advanced setting.
-
- See :mod:`gevent.os` for a detailed description.
- """
- name = 'disable_watch_children'
- environment_key = 'GEVENT_NOWAITPID'
- default = False
-
-
-class TraceMalloc(IntSettingMixin, Setting):
- name = 'trace_malloc'
- environment_key = 'PYTHONTRACEMALLOC'
- default = False
-
- desc = """\
- Should FFI objects track their allocation?
-
- This is only useful for low-level debugging.
-
- On Python 3, this environment variable is built in to the
- interpreter, and it may also be set with the ``-X
- tracemalloc`` command line argument.
-
- On Python 2, gevent interprets this argument and adds extra
- tracking information for FFI objects.
- """
-
-
-class TrackGreenletTree(BoolSettingMixin, Setting):
- name = 'track_greenlet_tree'
- environment_key = 'GEVENT_TRACK_GREENLET_TREE'
- default = True
-
- desc = """\
- Should `Greenlet` objects track their spawning tree?
-
- Setting this to a false value will make spawning `Greenlet`
- objects and using `spawn_raw` faster, but the
- ``spawning_greenlet``, ``spawn_tree_locals`` and ``spawning_stack``
- will not be captured.
-
- .. versionadded:: 1.3b1
- """
-
-
-## Monitoring settings
-# All env keys should begin with GEVENT_MONITOR
-
-class MonitorThread(BoolSettingMixin, Setting):
- name = 'monitor_thread'
- environment_key = 'GEVENT_MONITOR_THREAD_ENABLE'
- default = False
-
- desc = """\
- Should each hub start a native OS thread to monitor
- for problems?
-
- Such a thread will periodically check to see if the event loop
- is blocked for longer than `max_blocking_time`, producing output on
- the hub's exception stream (stderr by default) if it detects this condition.
-
- If this setting is true, then this thread will be created
- the first time the hub is switched to,
- or you can call :meth:`gevent.hub.Hub.start_periodic_monitoring_thread` at any
- time to create it (from the same thread that will run the hub). That function
- will return an instance of :class:`gevent.events.IPeriodicMonitorThread`
- to which you can add your own monitoring functions. That function
- also emits an event of :class:`gevent.events.PeriodicMonitorThreadStartedEvent`.
-
- .. seealso:: `max_blocking_time`
-
- .. versionadded:: 1.3b1
- """
-
-class MaxBlockingTime(FloatSettingMixin, Setting):
- name = 'max_blocking_time'
- # This environment key doesn't follow the convention because it's
- # meant to match a key used by existing projects
- environment_key = 'GEVENT_MAX_BLOCKING_TIME'
- default = 0.1
-
- desc = """\
- If the `monitor_thread` is enabled, this is
- approximately how long (in seconds)
- the event loop will be allowed to block before a warning is issued.
-
- This function depends on using `greenlet.settrace`, so installing
- your own trace function after starting the monitoring thread will
- cause this feature to misbehave unless you call the function
- returned by `greenlet.settrace`. If you install a tracing function *before*
- the monitoring thread is started, it will still be called.
-
- .. note:: In the unlikely event of creating and using multiple different
- gevent hubs in the same native thread in a short period of time,
- especially without destroying the hubs, false positives may be reported.
-
- .. versionadded:: 1.3b1
- """
-
-class MonitorMemoryPeriod(FloatSettingMixin, Setting):
- name = 'memory_monitor_period'
-
- environment_key = 'GEVENT_MONITOR_MEMORY_PERIOD'
- default = 5
-
- desc = """\
- If `monitor_thread` is enabled, this is approximately how long
- (in seconds) we will go between checking the processes memory usage.
-
- Checking the memory usage is relatively expensive on some operating
- systems, so this should not be too low. gevent will place a floor
- value on it.
- """
-
-class MonitorMemoryMaxUsage(ByteCountSettingMixin, Setting):
- name = 'max_memory_usage'
-
- environment_key = 'GEVENT_MONITOR_MEMORY_MAX'
- default = None
-
- desc = """\
- If `monitor_thread` is enabled,
- then if memory usage exceeds this amount (in bytes), events will
- be emitted. See `gevent.events`. In the environment variable, you can use
- a suffix of 'kb', 'mb' or 'gb' to specify the value in kilobytes, megabytes
- or gigibytes.
-
- There is no default value for this setting. If you wish to
- cap memory usage, you must choose a value.
- """
-
-# The ares settings are all interpreted by
-# gevent/resolver/ares.pyx, so we don't do
-# any validation here.
-
-class AresSettingMixin(object):
-
- document = False
-
- @property
- def kwarg_name(self):
- return self.name[5:]
-
- validate = staticmethod(validate_anything)
-
- _convert = staticmethod(convert_str_value_as_is)
-
-class AresFlags(AresSettingMixin, Setting):
- name = 'ares_flags'
- default = None
- environment_key = 'GEVENTARES_FLAGS'
-
-class AresTimeout(AresSettingMixin, Setting):
- document = True
- name = 'ares_timeout'
- default = None
- environment_key = 'GEVENTARES_TIMEOUT'
- desc = """\
-
- .. deprecated:: 1.3a2
- Prefer the :attr:`resolver_timeout` setting. If both are set,
- the results are not defined.
- """
-
-class AresTries(AresSettingMixin, Setting):
- name = 'ares_tries'
- default = None
- environment_key = 'GEVENTARES_TRIES'
-
-class AresNdots(AresSettingMixin, Setting):
- name = 'ares_ndots'
- default = None
- environment_key = 'GEVENTARES_NDOTS'
-
-class AresUDPPort(AresSettingMixin, Setting):
- name = 'ares_udp_port'
- default = None
- environment_key = 'GEVENTARES_UDP_PORT'
-
-class AresTCPPort(AresSettingMixin, Setting):
- name = 'ares_tcp_port'
- default = None
- environment_key = 'GEVENTARES_TCP_PORT'
-
-class AresServers(AresSettingMixin, Setting):
- document = True
- name = 'ares_servers'
- default = None
- environment_key = 'GEVENTARES_SERVERS'
- desc = """\
- A list of strings giving the IP addresses of nameservers for the ares resolver.
-
- In the environment variable, these strings are separated by commas.
-
- .. deprecated:: 1.3a2
- Prefer the :attr:`resolver_nameservers` setting. If both are set,
- the results are not defined.
- """
-
-# Generic nameservers, works for dnspython and ares.
-class ResolverNameservers(AresSettingMixin, Setting):
- document = True
- name = 'resolver_nameservers'
- default = None
- environment_key = 'GEVENT_RESOLVER_NAMESERVERS'
- desc = """\
- A list of strings giving the IP addresses of nameservers for the (non-system) resolver.
-
- In the environment variable, these strings are separated by commas.
-
- .. rubric:: Resolver Behaviour
-
- * blocking
-
- Ignored
-
- * Threaded
-
- Ignored
-
- * dnspython
-
- If this setting is not given, the dnspython resolver will
- load nameservers to use from ``/etc/resolv.conf``
- or the Windows registry. This setting replaces any nameservers read
- from those means. Note that the file and registry are still read
- for other settings.
-
- .. caution:: dnspython does not validate the members of the list.
- An improper address (such as a hostname instead of IP) has
- undefined results, including hanging the process.
-
- * ares
-
- Similar to dnspython, but with more platform and compile-time
- options. ares validates that the members of the list are valid
- addresses.
- """
-
- # Normal string-to-list rules. But still validate_anything.
- _convert = Setting._convert
-
- # TODO: In the future, support reading a resolv.conf file
- # *other* than /etc/resolv.conf, and do that both on Windows
- # and other platforms. Also offer the option to disable the system
- # configuration entirely.
-
- @property
- def kwarg_name(self):
- return 'servers'
-
-# Generic timeout, works for dnspython and ares
-class ResolverTimeout(FloatSettingMixin, AresSettingMixin, Setting):
- document = True
- name = 'resolver_timeout'
- environment_key = 'GEVENT_RESOLVER_TIMEOUT'
- desc = """\
- The total amount of time that the DNS resolver will spend making queries.
-
- Only the ares and dnspython resolvers support this.
-
- .. versionadded:: 1.3a2
- """
-
- @property
- def kwarg_name(self):
- return 'timeout'
-
-config = Config()
-
-# Go ahead and attempt to import the loop when this class is
-# instantiated. The hub won't work if the loop can't be found. This
-# can solve problems with the class being imported from multiple
-# threads at once, leading to one of the imports failing.
-# factories are themselves handled lazily. See #687.
-
-# Don't cache it though, in case the user re-configures through the
-# API.
-
-try:
- Loop().get()
-except ImportError: # pragma: no cover
- pass