python学习

This commit is contained in:
2019-07-17 16:36:59 +08:00
commit 596a0bf6bf
786 changed files with 300160 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
# util/__init__.py
# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
from collections import defaultdict # noqa
from contextlib import contextmanager # noqa
from functools import partial # noqa
from functools import update_wrapper # noqa
from ._collections import coerce_generator_arg # noqa
from ._collections import collections_abc # noqa
from ._collections import column_dict # noqa
from ._collections import column_set # noqa
from ._collections import EMPTY_SET # noqa
from ._collections import flatten_iterator # noqa
from ._collections import has_dupes # noqa
from ._collections import has_intersection # noqa
from ._collections import IdentitySet # noqa
from ._collections import ImmutableContainer # noqa
from ._collections import immutabledict # noqa
from ._collections import ImmutableProperties # noqa
from ._collections import KeyedTuple # noqa
from ._collections import lightweight_named_tuple # noqa
from ._collections import LRUCache # noqa
from ._collections import ordered_column_set # noqa
from ._collections import OrderedDict # noqa
from ._collections import OrderedIdentitySet # noqa
from ._collections import OrderedProperties # noqa
from ._collections import OrderedSet # noqa
from ._collections import populate_column_dict # noqa
from ._collections import PopulateDict # noqa
from ._collections import Properties # noqa
from ._collections import ScopedRegistry # noqa
from ._collections import ThreadLocalRegistry # noqa
from ._collections import to_column_set # noqa
from ._collections import to_list # noqa
from ._collections import to_set # noqa
from ._collections import unique_list # noqa
from ._collections import UniqueAppender # noqa
from ._collections import update_copy # noqa
from ._collections import WeakSequence # noqa
from .compat import b # noqa
from .compat import b64decode # noqa
from .compat import b64encode # noqa
from .compat import binary_type # noqa
from .compat import byte_buffer # noqa
from .compat import callable # noqa
from .compat import cmp # noqa
from .compat import cpython # noqa
from .compat import decode_backslashreplace # noqa
from .compat import dottedgetter # noqa
from .compat import inspect_getfullargspec # noqa
from .compat import int_types # noqa
from .compat import iterbytes # noqa
from .compat import itertools_filter # noqa
from .compat import itertools_filterfalse # noqa
from .compat import jython # noqa
from .compat import namedtuple # noqa
from .compat import nested # noqa
from .compat import next # noqa
from .compat import parse_qsl # noqa
from .compat import pickle # noqa
from .compat import print_ # noqa
from .compat import py2k # noqa
from .compat import py33 # noqa
from .compat import py36 # noqa
from .compat import py3k # noqa
from .compat import pypy # noqa
from .compat import quote_plus # noqa
from .compat import raise_from_cause # noqa
from .compat import reduce # noqa
from .compat import reraise # noqa
from .compat import safe_kwarg # noqa
from .compat import string_types # noqa
from .compat import StringIO # noqa
from .compat import text_type # noqa
from .compat import threading # noqa
from .compat import u # noqa
from .compat import ue # noqa
from .compat import unquote # noqa
from .compat import unquote_plus # noqa
from .compat import win32 # noqa
from .compat import with_metaclass # noqa
from .compat import zip_longest # noqa
from .deprecations import deprecated # noqa
from .deprecations import deprecated_cls # noqa
from .deprecations import deprecated_params # noqa
from .deprecations import inject_docstring_text # noqa
from .deprecations import pending_deprecation # noqa
from .deprecations import warn_deprecated # noqa
from .deprecations import warn_pending_deprecation # noqa
from .langhelpers import add_parameter_text # noqa
from .langhelpers import as_interface # noqa
from .langhelpers import asbool # noqa
from .langhelpers import asint # noqa
from .langhelpers import assert_arg_type # noqa
from .langhelpers import attrsetter # noqa
from .langhelpers import bool_or_str # noqa
from .langhelpers import chop_traceback # noqa
from .langhelpers import class_hierarchy # noqa
from .langhelpers import classproperty # noqa
from .langhelpers import clsname_as_plain_name # noqa
from .langhelpers import coerce_kw_type # noqa
from .langhelpers import constructor_copy # noqa
from .langhelpers import counter # noqa
from .langhelpers import decode_slice # noqa
from .langhelpers import decorator # noqa
from .langhelpers import dependencies # noqa
from .langhelpers import dictlike_iteritems # noqa
from .langhelpers import duck_type_collection # noqa
from .langhelpers import ellipses_string # noqa
from .langhelpers import EnsureKWArgType # noqa
from .langhelpers import format_argspec_init # noqa
from .langhelpers import format_argspec_plus # noqa
from .langhelpers import generic_repr # noqa
from .langhelpers import get_callable_argspec # noqa
from .langhelpers import get_cls_kwargs # noqa
from .langhelpers import get_func_kwargs # noqa
from .langhelpers import getargspec_init # noqa
from .langhelpers import group_expirable_memoized_property # noqa
from .langhelpers import hybridmethod # noqa
from .langhelpers import hybridproperty # noqa
from .langhelpers import iterate_attributes # noqa
from .langhelpers import map_bits # noqa
from .langhelpers import md5_hex # noqa
from .langhelpers import memoized_instancemethod # noqa
from .langhelpers import memoized_property # noqa
from .langhelpers import MemoizedSlots # noqa
from .langhelpers import methods_equivalent # noqa
from .langhelpers import monkeypatch_proxied_specials # noqa
from .langhelpers import NoneType # noqa
from .langhelpers import only_once # noqa
from .langhelpers import PluginLoader # noqa
from .langhelpers import portable_instancemethod # noqa
from .langhelpers import quoted_token_parser # noqa
from .langhelpers import safe_reraise # noqa
from .langhelpers import set_creation_order # noqa
from .langhelpers import symbol # noqa
from .langhelpers import unbound_method_to_callable # noqa
from .langhelpers import warn # noqa
from .langhelpers import warn_exception # noqa
from .langhelpers import warn_limited # noqa
from .langhelpers import wrap_callable # noqa
# things that used to be not always available,
# but are now as of current support Python versions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,420 @@
# util/compat.py
# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Handle Python version/platform incompatibilities."""
import collections
import contextlib
import inspect
import operator
import sys
py36 = sys.version_info >= (3, 6)
py33 = sys.version_info >= (3, 3)
py35 = sys.version_info >= (3, 5)
py32 = sys.version_info >= (3, 2)
py3k = sys.version_info >= (3, 0)
py2k = sys.version_info < (3, 0)
py265 = sys.version_info >= (2, 6, 5)
jython = sys.platform.startswith("java")
pypy = hasattr(sys, "pypy_version_info")
win32 = sys.platform.startswith("win")
cpython = not pypy and not jython # TODO: something better for this ?
contextmanager = contextlib.contextmanager
dottedgetter = operator.attrgetter
namedtuple = collections.namedtuple
next = next # noqa
FullArgSpec = collections.namedtuple(
"FullArgSpec",
[
"args",
"varargs",
"varkw",
"defaults",
"kwonlyargs",
"kwonlydefaults",
"annotations",
],
)
try:
import threading
except ImportError:
import dummy_threading as threading # noqa
# work around http://bugs.python.org/issue2646
if py265:
safe_kwarg = lambda arg: arg # noqa
else:
safe_kwarg = str
def inspect_getfullargspec(func):
"""Fully vendored version of getfullargspec from Python 3.3."""
if inspect.ismethod(func):
func = func.__func__
if not inspect.isfunction(func):
raise TypeError("{!r} is not a Python function".format(func))
co = func.__code__
if not inspect.iscode(co):
raise TypeError("{!r} is not a code object".format(co))
nargs = co.co_argcount
names = co.co_varnames
nkwargs = co.co_kwonlyargcount if py3k else 0
args = list(names[:nargs])
kwonlyargs = list(names[nargs : nargs + nkwargs])
step = 0
nargs += nkwargs
varargs = None
if co.co_flags & inspect.CO_VARARGS:
varargs = co.co_varnames[nargs]
nargs = nargs + 1
varkw = None
if co.co_flags & inspect.CO_VARKEYWORDS:
varkw = co.co_varnames[nargs]
return FullArgSpec(
args,
varargs,
varkw,
func.__defaults__,
kwonlyargs,
func.__kwdefaults__ if py3k else None,
func.__annotations__ if py3k else {},
)
if py3k:
import base64
import builtins
import configparser
import itertools
import pickle
from functools import reduce
from io import BytesIO as byte_buffer
from io import StringIO
from itertools import zip_longest
from urllib.parse import (
quote_plus,
unquote_plus,
parse_qsl,
quote,
unquote,
)
string_types = (str,)
binary_types = (bytes,)
binary_type = bytes
text_type = str
int_types = (int,)
iterbytes = iter
itertools_filterfalse = itertools.filterfalse
itertools_filter = filter
itertools_imap = map
exec_ = getattr(builtins, "exec")
import_ = getattr(builtins, "__import__")
print_ = getattr(builtins, "print")
def b(s):
return s.encode("latin-1")
def b64decode(x):
return base64.b64decode(x.encode("ascii"))
def b64encode(x):
return base64.b64encode(x).decode("ascii")
def decode_backslashreplace(text, encoding):
return text.decode(encoding, errors="backslashreplace")
def cmp(a, b):
return (a > b) - (a < b)
def reraise(tp, value, tb=None, cause=None):
if cause is not None:
assert cause is not value, "Same cause emitted"
value.__cause__ = cause
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
def u(s):
return s
def ue(s):
return s
if py32:
callable = callable # noqa
else:
def callable(fn): # noqa
return hasattr(fn, "__call__")
else:
import base64
import ConfigParser as configparser # noqa
import itertools
from StringIO import StringIO # noqa
from cStringIO import StringIO as byte_buffer # noqa
from itertools import izip_longest as zip_longest # noqa
from urllib import quote # noqa
from urllib import quote_plus # noqa
from urllib import unquote # noqa
from urllib import unquote_plus # noqa
from urlparse import parse_qsl # noqa
try:
import cPickle as pickle
except ImportError:
import pickle # noqa
string_types = (basestring,) # noqa
binary_types = (bytes,)
binary_type = str
text_type = unicode # noqa
int_types = int, long # noqa
callable = callable # noqa
cmp = cmp # noqa
reduce = reduce # noqa
b64encode = base64.b64encode
b64decode = base64.b64decode
itertools_filterfalse = itertools.ifilterfalse
itertools_filter = itertools.ifilter
itertools_imap = itertools.imap
def b(s):
return s
def exec_(func_text, globals_, lcl=None):
if lcl is None:
exec("exec func_text in globals_")
else:
exec("exec func_text in globals_, lcl")
def iterbytes(buf):
return (ord(byte) for byte in buf)
def import_(*args):
if len(args) == 4:
args = args[0:3] + ([str(arg) for arg in args[3]],)
return __import__(*args)
def print_(*args, **kwargs):
fp = kwargs.pop("file", sys.stdout)
if fp is None:
return
for arg in enumerate(args):
if not isinstance(arg, basestring): # noqa
arg = str(arg)
fp.write(arg)
def u(s):
# this differs from what six does, which doesn't support non-ASCII
# strings - we only use u() with
# literal source strings, and all our source files with non-ascii
# in them (all are tests) are utf-8 encoded.
return unicode(s, "utf-8") # noqa
def ue(s):
return unicode(s, "unicode_escape") # noqa
def decode_backslashreplace(text, encoding):
try:
return text.decode(encoding)
except UnicodeDecodeError:
# regular "backslashreplace" for an incompatible encoding raises:
# "TypeError: don't know how to handle UnicodeDecodeError in
# error callback"
return repr(text)[1:-1].decode()
def safe_bytestring(text):
# py2k only
if not isinstance(text, string_types):
return unicode(text).encode("ascii", errors="backslashreplace")
elif isinstance(text, unicode):
return text.encode("ascii", errors="backslashreplace")
else:
return text
# not as nice as that of Py3K, but at least preserves
# the code line where the issue occurred
exec(
"def reraise(tp, value, tb=None, cause=None):\n"
" if cause is not None:\n"
" assert cause is not value, 'Same cause emitted'\n"
" raise tp, value, tb\n"
)
if py35:
from inspect import formatannotation
def inspect_formatargspec(
args,
varargs=None,
varkw=None,
defaults=None,
kwonlyargs=(),
kwonlydefaults={},
annotations={},
formatarg=str,
formatvarargs=lambda name: "*" + name,
formatvarkw=lambda name: "**" + name,
formatvalue=lambda value: "=" + repr(value),
formatreturns=lambda text: " -> " + text,
formatannotation=formatannotation,
):
"""Copy formatargspec from python 3.7 standard library.
Python 3 has deprecated formatargspec and requested that Signature
be used instead, however this requires a full reimplementation
of formatargspec() in terms of creating Parameter objects and such.
Instead of introducing all the object-creation overhead and having
to reinvent from scratch, just copy their compatibility routine.
Utimately we would need to rewrite our "decorator" routine completely
which is not really worth it right now, until all Python 2.x support
is dropped.
"""
def formatargandannotation(arg):
result = formatarg(arg)
if arg in annotations:
result += ": " + formatannotation(annotations[arg])
return result
specs = []
if defaults:
firstdefault = len(args) - len(defaults)
for i, arg in enumerate(args):
spec = formatargandannotation(arg)
if defaults and i >= firstdefault:
spec = spec + formatvalue(defaults[i - firstdefault])
specs.append(spec)
if varargs is not None:
specs.append(formatvarargs(formatargandannotation(varargs)))
else:
if kwonlyargs:
specs.append("*")
if kwonlyargs:
for kwonlyarg in kwonlyargs:
spec = formatargandannotation(kwonlyarg)
if kwonlydefaults and kwonlyarg in kwonlydefaults:
spec += formatvalue(kwonlydefaults[kwonlyarg])
specs.append(spec)
if varkw is not None:
specs.append(formatvarkw(formatargandannotation(varkw)))
result = "(" + ", ".join(specs) + ")"
if "return" in annotations:
result += formatreturns(formatannotation(annotations["return"]))
return result
elif py2k:
from inspect import formatargspec as _inspect_formatargspec
def inspect_formatargspec(*spec, **kw):
# convert for a potential FullArgSpec from compat.getfullargspec()
return _inspect_formatargspec(*spec[0:4], **kw) # noqa
else:
from inspect import formatargspec as inspect_formatargspec # noqa
# Fix deprecation of accessing ABCs straight from collections module
# (which will stop working in 3.8).
if py33:
import collections.abc as collections_abc
else:
import collections as collections_abc # noqa
@contextlib.contextmanager
def nested(*managers):
"""Implement contextlib.nested, mostly for unit tests.
As tests still need to run on py2.6 we can't use multiple-with yet.
Function is removed in py3k but also emits deprecation warning in 2.7
so just roll it here for everyone.
"""
exits = []
vars_ = []
exc = (None, None, None)
try:
for mgr in managers:
exit_ = mgr.__exit__
enter = mgr.__enter__
vars_.append(enter())
exits.append(exit_)
yield vars_
except:
exc = sys.exc_info()
finally:
while exits:
exit_ = exits.pop() # noqa
try:
if exit_(*exc):
exc = (None, None, None)
except:
exc = sys.exc_info()
if exc != (None, None, None):
reraise(exc[0], exc[1], exc[2])
def raise_from_cause(exception, exc_info=None):
if exc_info is None:
exc_info = sys.exc_info()
exc_type, exc_value, exc_tb = exc_info
cause = exc_value if exc_value is not exception else None
reraise(type(exception), exception, tb=exc_tb, cause=cause)
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass.
Drops the middle class upon creation.
Source: http://lucumr.pocoo.org/2013/5/21/porting-to-python-3-redux/
"""
class metaclass(meta):
__call__ = type.__call__
__init__ = type.__init__
def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass("temporary_class", None, {})

View File

@@ -0,0 +1,250 @@
# util/deprecations.py
# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Helpers related to deprecation of functions, methods, classes, other
functionality."""
import re
import warnings
from . import compat
from .langhelpers import decorator
from .langhelpers import inject_docstring_text
from .langhelpers import inject_param_text
from .. import exc
def warn_deprecated(msg, stacklevel=3):
warnings.warn(msg, exc.SADeprecationWarning, stacklevel=stacklevel)
def warn_pending_deprecation(msg, stacklevel=3):
warnings.warn(msg, exc.SAPendingDeprecationWarning, stacklevel=stacklevel)
def deprecated_cls(version, message, constructor="__init__"):
header = ".. deprecated:: %s %s" % (version, (message or ""))
def decorate(cls):
return _decorate_cls_with_warning(
cls,
constructor,
exc.SADeprecationWarning,
message % dict(func=constructor),
header,
)
return decorate
def deprecated(version, message=None, add_deprecation_to_docstring=True):
"""Decorates a function and issues a deprecation warning on use.
:param version:
Issue version in the warning.
:param message:
If provided, issue message in the warning. A sensible default
is used if not provided.
:param add_deprecation_to_docstring:
Default True. If False, the wrapped function's __doc__ is left
as-is. If True, the 'message' is prepended to the docs if
provided, or sensible default if message is omitted.
"""
if add_deprecation_to_docstring:
header = ".. deprecated:: %s %s" % (version, (message or ""))
else:
header = None
if message is None:
message = "Call to deprecated function %(func)s"
def decorate(fn):
return _decorate_with_warning(
fn,
exc.SADeprecationWarning,
message % dict(func=fn.__name__),
header,
)
return decorate
def deprecated_params(**specs):
"""Decorates a function to warn on use of certain parameters.
e.g. ::
@deprecated_params(
weak_identity_map=(
"0.7",
"the :paramref:`.Session.weak_identity_map parameter "
"is deprecated."
)
)
"""
messages = {}
for param, (version, message) in specs.items():
messages[param] = _sanitize_restructured_text(message)
def decorate(fn):
spec = compat.inspect_getfullargspec(fn)
if spec.defaults is not None:
defaults = dict(
zip(
spec.args[(len(spec.args) - len(spec.defaults)) :],
spec.defaults,
)
)
check_defaults = set(defaults).intersection(messages)
check_kw = set(messages).difference(defaults)
else:
check_defaults = ()
check_kw = set(messages)
has_kw = spec.varkw is not None
@decorator
def warned(fn, *args, **kwargs):
for m in check_defaults:
if kwargs[m] != defaults[m]:
warnings.warn(
messages[m], exc.SADeprecationWarning, stacklevel=3
)
for m in check_kw:
if m in kwargs:
warnings.warn(
messages[m], exc.SADeprecationWarning, stacklevel=3
)
return fn(*args, **kwargs)
doc = fn.__doc__ is not None and fn.__doc__ or ""
if doc:
doc = inject_param_text(
doc,
{
param: ".. deprecated:: %s %s" % (version, (message or ""))
for param, (version, message) in specs.items()
},
)
decorated = warned(fn)
decorated.__doc__ = doc
return decorated
return decorate
def pending_deprecation(
version, message=None, add_deprecation_to_docstring=True
):
"""Decorates a function and issues a pending deprecation warning on use.
:param version:
An approximate future version at which point the pending deprecation
will become deprecated. Not used in messaging.
:param message:
If provided, issue message in the warning. A sensible default
is used if not provided.
:param add_deprecation_to_docstring:
Default True. If False, the wrapped function's __doc__ is left
as-is. If True, the 'message' is prepended to the docs if
provided, or sensible default if message is omitted.
"""
if add_deprecation_to_docstring:
header = ".. deprecated:: %s (pending) %s" % (version, (message or ""))
else:
header = None
if message is None:
message = "Call to deprecated function %(func)s"
def decorate(fn):
return _decorate_with_warning(
fn,
exc.SAPendingDeprecationWarning,
message % dict(func=fn.__name__),
header,
)
return decorate
def deprecated_option_value(parameter_value, default_value, warning_text):
if parameter_value is None:
return default_value
else:
warn_deprecated(warning_text)
return parameter_value
def _sanitize_restructured_text(text):
def repl(m):
type_, name = m.group(1, 2)
if type_ in ("func", "meth"):
name += "()"
return name
return re.sub(r"\:(\w+)\:`~?\.?(.+?)`", repl, text)
def _decorate_cls_with_warning(
cls, constructor, wtype, message, docstring_header=None
):
doc = cls.__doc__ is not None and cls.__doc__ or ""
if docstring_header is not None:
docstring_header %= dict(func=constructor)
doc = inject_docstring_text(doc, docstring_header, 1)
if type(cls) is type:
clsdict = dict(cls.__dict__)
clsdict["__doc__"] = doc
cls = type(cls.__name__, cls.__bases__, clsdict)
constructor_fn = clsdict[constructor]
else:
cls.__doc__ = doc
constructor_fn = getattr(cls, constructor)
setattr(
cls,
constructor,
_decorate_with_warning(constructor_fn, wtype, message, None),
)
return cls
def _decorate_with_warning(func, wtype, message, docstring_header=None):
"""Wrap a function with a warnings.warn and augmented docstring."""
message = _sanitize_restructured_text(message)
@decorator
def warned(fn, *args, **kwargs):
warnings.warn(message, wtype, stacklevel=3)
return fn(*args, **kwargs)
doc = func.__doc__ is not None and func.__doc__ or ""
if docstring_header is not None:
docstring_header %= dict(func=func.__name__)
doc = inject_docstring_text(doc, docstring_header, 1)
decorated = warned(func)
decorated.__doc__ = doc
decorated._sa_warn = lambda: warnings.warn(message, wtype, stacklevel=3)
return decorated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,209 @@
# util/queue.py
# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""An adaptation of Py2.3/2.4's Queue module which supports reentrant
behavior, using RLock instead of Lock for its mutex object. The
Queue object is used exclusively by the sqlalchemy.pool.QueuePool
class.
This is to support the connection pool's usage of weakref callbacks to return
connections to the underlying Queue, which can in extremely
rare cases be invoked within the ``get()`` method of the Queue itself,
producing a ``put()`` inside the ``get()`` and therefore a reentrant
condition.
"""
from collections import deque
from time import time as _time
from .compat import threading
__all__ = ["Empty", "Full", "Queue"]
class Empty(Exception):
"Exception raised by Queue.get(block=0)/get_nowait()."
pass
class Full(Exception):
"Exception raised by Queue.put(block=0)/put_nowait()."
pass
class Queue:
def __init__(self, maxsize=0, use_lifo=False):
"""Initialize a queue object with a given maximum size.
If `maxsize` is <= 0, the queue size is infinite.
If `use_lifo` is True, this Queue acts like a Stack (LIFO).
"""
self._init(maxsize)
# mutex must be held whenever the queue is mutating. All methods
# that acquire mutex must release it before returning. mutex
# is shared between the two conditions, so acquiring and
# releasing the conditions also acquires and releases mutex.
self.mutex = threading.RLock()
# Notify not_empty whenever an item is added to the queue; a
# thread waiting to get is notified then.
self.not_empty = threading.Condition(self.mutex)
# Notify not_full whenever an item is removed from the queue;
# a thread waiting to put is notified then.
self.not_full = threading.Condition(self.mutex)
# If this queue uses LIFO or FIFO
self.use_lifo = use_lifo
def qsize(self):
"""Return the approximate size of the queue (not reliable!)."""
self.mutex.acquire()
n = self._qsize()
self.mutex.release()
return n
def empty(self):
"""Return True if the queue is empty, False otherwise (not
reliable!)."""
self.mutex.acquire()
n = self._empty()
self.mutex.release()
return n
def full(self):
"""Return True if the queue is full, False otherwise (not
reliable!)."""
self.mutex.acquire()
n = self._full()
self.mutex.release()
return n
def put(self, item, block=True, timeout=None):
"""Put an item into the queue.
If optional args `block` is True and `timeout` is None (the
default), block if necessary until a free slot is
available. If `timeout` is a positive number, it blocks at
most `timeout` seconds and raises the ``Full`` exception if no
free slot was available within that time. Otherwise (`block`
is false), put an item on the queue if a free slot is
immediately available, else raise the ``Full`` exception
(`timeout` is ignored in that case).
"""
self.not_full.acquire()
try:
if not block:
if self._full():
raise Full
elif timeout is None:
while self._full():
self.not_full.wait()
else:
if timeout < 0:
raise ValueError("'timeout' must be a positive number")
endtime = _time() + timeout
while self._full():
remaining = endtime - _time()
if remaining <= 0.0:
raise Full
self.not_full.wait(remaining)
self._put(item)
self.not_empty.notify()
finally:
self.not_full.release()
def put_nowait(self, item):
"""Put an item into the queue without blocking.
Only enqueue the item if a free slot is immediately available.
Otherwise raise the ``Full`` exception.
"""
return self.put(item, False)
def get(self, block=True, timeout=None):
"""Remove and return an item from the queue.
If optional args `block` is True and `timeout` is None (the
default), block if necessary until an item is available. If
`timeout` is a positive number, it blocks at most `timeout`
seconds and raises the ``Empty`` exception if no item was
available within that time. Otherwise (`block` is false),
return an item if one is immediately available, else raise the
``Empty`` exception (`timeout` is ignored in that case).
"""
self.not_empty.acquire()
try:
if not block:
if self._empty():
raise Empty
elif timeout is None:
while self._empty():
self.not_empty.wait()
else:
if timeout < 0:
raise ValueError("'timeout' must be a positive number")
endtime = _time() + timeout
while self._empty():
remaining = endtime - _time()
if remaining <= 0.0:
raise Empty
self.not_empty.wait(remaining)
item = self._get()
self.not_full.notify()
return item
finally:
self.not_empty.release()
def get_nowait(self):
"""Remove and return an item from the queue without blocking.
Only get an item if one is immediately available. Otherwise
raise the ``Empty`` exception.
"""
return self.get(False)
# Override these methods to implement other queue organizations
# (e.g. stack or priority queue).
# These will only be called with appropriate locks held
# Initialize the queue representation
def _init(self, maxsize):
self.maxsize = maxsize
self.queue = deque()
def _qsize(self):
return len(self.queue)
# Check whether the queue is empty
def _empty(self):
return not self.queue
# Check whether the queue is full
def _full(self):
return self.maxsize > 0 and len(self.queue) == self.maxsize
# Put a new item in the queue
def _put(self, item):
self.queue.append(item)
# Get an item from the queue
def _get(self):
if self.use_lifo:
# LIFO
return self.queue.pop()
else:
# FIFO
return self.queue.popleft()

View File

@@ -0,0 +1,97 @@
# util/topological.py
# Copyright (C) 2005-2019 the SQLAlchemy authors and contributors
# <see AUTHORS file>
#
# This module is part of SQLAlchemy and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
"""Topological sorting algorithms."""
from .. import util
from ..exc import CircularDependencyError
__all__ = ["sort", "sort_as_subsets", "find_cycles"]
def sort_as_subsets(tuples, allitems, deterministic_order=False):
edges = util.defaultdict(set)
for parent, child in tuples:
edges[child].add(parent)
Set = util.OrderedSet if deterministic_order else set
todo = Set(allitems)
while todo:
output = Set()
for node in todo:
if todo.isdisjoint(edges[node]):
output.add(node)
if not output:
raise CircularDependencyError(
"Circular dependency detected.",
find_cycles(tuples, allitems),
_gen_edges(edges),
)
todo.difference_update(output)
yield output
def sort(tuples, allitems, deterministic_order=False):
"""sort the given list of items by dependency.
'tuples' is a list of tuples representing a partial ordering.
'deterministic_order' keeps items within a dependency tier in list order.
"""
for set_ in sort_as_subsets(tuples, allitems, deterministic_order):
for s in set_:
yield s
def find_cycles(tuples, allitems):
# adapted from:
# http://neopythonic.blogspot.com/2009/01/detecting-cycles-in-directed-graph.html
edges = util.defaultdict(set)
for parent, child in tuples:
edges[parent].add(child)
nodes_to_test = set(edges)
output = set()
# we'd like to find all nodes that are
# involved in cycles, so we do the full
# pass through the whole thing for each
# node in the original list.
# we can go just through parent edge nodes.
# if a node is only a child and never a parent,
# by definition it can't be part of a cycle. same
# if it's not in the edges at all.
for node in nodes_to_test:
stack = [node]
todo = nodes_to_test.difference(stack)
while stack:
top = stack[-1]
for node in edges[top]:
if node in stack:
cyc = stack[stack.index(node) :]
todo.difference_update(cyc)
output.update(cyc)
if node in todo:
stack.append(node)
todo.remove(node)
break
else:
node = stack.pop()
return output
def _gen_edges(edges):
return set([(right, left) for left in edges for right in edges[left]])