Загрузить файлы в «venv/Lib/site-packages/sqlalchemy/util»
This commit is contained in:
162
venv/Lib/site-packages/sqlalchemy/util/__init__.py
Normal file
162
venv/Lib/site-packages/sqlalchemy/util/__init__.py
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# util/__init__.py
|
||||||
|
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
||||||
|
# <see AUTHORS file>
|
||||||
|
#
|
||||||
|
# This module is part of SQLAlchemy and is released under
|
||||||
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
|
||||||
|
from collections import defaultdict as defaultdict
|
||||||
|
from functools import partial as partial
|
||||||
|
from functools import update_wrapper as update_wrapper
|
||||||
|
|
||||||
|
from . import preloaded as preloaded
|
||||||
|
from ._collections import coerce_generator_arg as coerce_generator_arg
|
||||||
|
from ._collections import coerce_to_immutabledict as coerce_to_immutabledict
|
||||||
|
from ._collections import column_dict as column_dict
|
||||||
|
from ._collections import column_set as column_set
|
||||||
|
from ._collections import EMPTY_DICT as EMPTY_DICT
|
||||||
|
from ._collections import EMPTY_SET as EMPTY_SET
|
||||||
|
from ._collections import FacadeDict as FacadeDict
|
||||||
|
from ._collections import flatten_iterator as flatten_iterator
|
||||||
|
from ._collections import has_dupes as has_dupes
|
||||||
|
from ._collections import has_intersection as has_intersection
|
||||||
|
from ._collections import IdentitySet as IdentitySet
|
||||||
|
from ._collections import immutabledict as immutabledict
|
||||||
|
from ._collections import LRUCache as LRUCache
|
||||||
|
from ._collections import merge_lists_w_ordering as merge_lists_w_ordering
|
||||||
|
from ._collections import NONE_SET as NONE_SET
|
||||||
|
from ._collections import ordered_column_set as ordered_column_set
|
||||||
|
from ._collections import OrderedDict as OrderedDict
|
||||||
|
from ._collections import OrderedIdentitySet as OrderedIdentitySet
|
||||||
|
from ._collections import OrderedProperties as OrderedProperties
|
||||||
|
from ._collections import OrderedSet as OrderedSet
|
||||||
|
from ._collections import PopulateDict as PopulateDict
|
||||||
|
from ._collections import Properties as Properties
|
||||||
|
from ._collections import ReadOnlyContainer as ReadOnlyContainer
|
||||||
|
from ._collections import ReadOnlyProperties as ReadOnlyProperties
|
||||||
|
from ._collections import ScopedRegistry as ScopedRegistry
|
||||||
|
from ._collections import sort_dictionary as sort_dictionary
|
||||||
|
from ._collections import ThreadLocalRegistry as ThreadLocalRegistry
|
||||||
|
from ._collections import to_column_set as to_column_set
|
||||||
|
from ._collections import to_list as to_list
|
||||||
|
from ._collections import to_set as to_set
|
||||||
|
from ._collections import unique_list as unique_list
|
||||||
|
from ._collections import UniqueAppender as UniqueAppender
|
||||||
|
from ._collections import update_copy as update_copy
|
||||||
|
from ._collections import WeakPopulateDict as WeakPopulateDict
|
||||||
|
from ._collections import WeakSequence as WeakSequence
|
||||||
|
from .compat import anext_ as anext_
|
||||||
|
from .compat import arm as arm
|
||||||
|
from .compat import b as b
|
||||||
|
from .compat import b64decode as b64decode
|
||||||
|
from .compat import b64encode as b64encode
|
||||||
|
from .compat import cmp as cmp
|
||||||
|
from .compat import cpython as cpython
|
||||||
|
from .compat import dataclass_fields as dataclass_fields
|
||||||
|
from .compat import decode_backslashreplace as decode_backslashreplace
|
||||||
|
from .compat import dottedgetter as dottedgetter
|
||||||
|
from .compat import freethreading as freethreading
|
||||||
|
from .compat import get_annotations as get_annotations
|
||||||
|
from .compat import has_refcount_gc as has_refcount_gc
|
||||||
|
from .compat import inspect_getfullargspec as inspect_getfullargspec
|
||||||
|
from .compat import is64bit as is64bit
|
||||||
|
from .compat import local_dataclass_fields as local_dataclass_fields
|
||||||
|
from .compat import mini_gil as mini_gil
|
||||||
|
from .compat import osx as osx
|
||||||
|
from .compat import py310 as py310
|
||||||
|
from .compat import py311 as py311
|
||||||
|
from .compat import py312 as py312
|
||||||
|
from .compat import py313 as py313
|
||||||
|
from .compat import py314 as py314
|
||||||
|
from .compat import py38 as py38
|
||||||
|
from .compat import py39 as py39
|
||||||
|
from .compat import pypy as pypy
|
||||||
|
from .compat import win32 as win32
|
||||||
|
from .concurrency import await_fallback as await_fallback
|
||||||
|
from .concurrency import await_only as await_only
|
||||||
|
from .concurrency import greenlet_spawn as greenlet_spawn
|
||||||
|
from .concurrency import is_exit_exception as is_exit_exception
|
||||||
|
from .deprecations import became_legacy_20 as became_legacy_20
|
||||||
|
from .deprecations import deprecated as deprecated
|
||||||
|
from .deprecations import deprecated_cls as deprecated_cls
|
||||||
|
from .deprecations import deprecated_params as deprecated_params
|
||||||
|
from .deprecations import moved_20 as moved_20
|
||||||
|
from .deprecations import warn_deprecated as warn_deprecated
|
||||||
|
from .langhelpers import add_parameter_text as add_parameter_text
|
||||||
|
from .langhelpers import as_interface as as_interface
|
||||||
|
from .langhelpers import asbool as asbool
|
||||||
|
from .langhelpers import asint as asint
|
||||||
|
from .langhelpers import assert_arg_type as assert_arg_type
|
||||||
|
from .langhelpers import attrsetter as attrsetter
|
||||||
|
from .langhelpers import bool_or_str as bool_or_str
|
||||||
|
from .langhelpers import chop_traceback as chop_traceback
|
||||||
|
from .langhelpers import class_hierarchy as class_hierarchy
|
||||||
|
from .langhelpers import classproperty as classproperty
|
||||||
|
from .langhelpers import clsname_as_plain_name as clsname_as_plain_name
|
||||||
|
from .langhelpers import coerce_kw_type as coerce_kw_type
|
||||||
|
from .langhelpers import constructor_copy as constructor_copy
|
||||||
|
from .langhelpers import constructor_key as constructor_key
|
||||||
|
from .langhelpers import counter as counter
|
||||||
|
from .langhelpers import create_proxy_methods as create_proxy_methods
|
||||||
|
from .langhelpers import decode_slice as decode_slice
|
||||||
|
from .langhelpers import decorator as decorator
|
||||||
|
from .langhelpers import dictlike_iteritems as dictlike_iteritems
|
||||||
|
from .langhelpers import duck_type_collection as duck_type_collection
|
||||||
|
from .langhelpers import ellipses_string as ellipses_string
|
||||||
|
from .langhelpers import EnsureKWArg as EnsureKWArg
|
||||||
|
from .langhelpers import FastIntFlag as FastIntFlag
|
||||||
|
from .langhelpers import format_argspec_init as format_argspec_init
|
||||||
|
from .langhelpers import format_argspec_plus as format_argspec_plus
|
||||||
|
from .langhelpers import generic_fn_descriptor as generic_fn_descriptor
|
||||||
|
from .langhelpers import generic_repr as generic_repr
|
||||||
|
from .langhelpers import get_callable_argspec as get_callable_argspec
|
||||||
|
from .langhelpers import get_cls_kwargs as get_cls_kwargs
|
||||||
|
from .langhelpers import get_func_kwargs as get_func_kwargs
|
||||||
|
from .langhelpers import getargspec_init as getargspec_init
|
||||||
|
from .langhelpers import has_compiled_ext as has_compiled_ext
|
||||||
|
from .langhelpers import HasMemoized as HasMemoized
|
||||||
|
from .langhelpers import (
|
||||||
|
HasMemoized_ro_memoized_attribute as HasMemoized_ro_memoized_attribute,
|
||||||
|
)
|
||||||
|
from .langhelpers import hybridmethod as hybridmethod
|
||||||
|
from .langhelpers import hybridproperty as hybridproperty
|
||||||
|
from .langhelpers import inject_docstring_text as inject_docstring_text
|
||||||
|
from .langhelpers import iterate_attributes as iterate_attributes
|
||||||
|
from .langhelpers import map_bits as map_bits
|
||||||
|
from .langhelpers import md5_hex as md5_hex
|
||||||
|
from .langhelpers import memoized_instancemethod as memoized_instancemethod
|
||||||
|
from .langhelpers import memoized_property as memoized_property
|
||||||
|
from .langhelpers import MemoizedSlots as MemoizedSlots
|
||||||
|
from .langhelpers import method_is_overridden as method_is_overridden
|
||||||
|
from .langhelpers import methods_equivalent as methods_equivalent
|
||||||
|
from .langhelpers import (
|
||||||
|
monkeypatch_proxied_specials as monkeypatch_proxied_specials,
|
||||||
|
)
|
||||||
|
from .langhelpers import non_memoized_property as non_memoized_property
|
||||||
|
from .langhelpers import NoneType as NoneType
|
||||||
|
from .langhelpers import only_once as only_once
|
||||||
|
from .langhelpers import (
|
||||||
|
parse_user_argument_for_enum as parse_user_argument_for_enum,
|
||||||
|
)
|
||||||
|
from .langhelpers import PluginLoader as PluginLoader
|
||||||
|
from .langhelpers import portable_instancemethod as portable_instancemethod
|
||||||
|
from .langhelpers import quoted_token_parser as quoted_token_parser
|
||||||
|
from .langhelpers import ro_memoized_property as ro_memoized_property
|
||||||
|
from .langhelpers import ro_non_memoized_property as ro_non_memoized_property
|
||||||
|
from .langhelpers import rw_hybridproperty as rw_hybridproperty
|
||||||
|
from .langhelpers import safe_reraise as safe_reraise
|
||||||
|
from .langhelpers import set_creation_order as set_creation_order
|
||||||
|
from .langhelpers import string_or_unprintable as string_or_unprintable
|
||||||
|
from .langhelpers import symbol as symbol
|
||||||
|
from .langhelpers import TypingOnly as TypingOnly
|
||||||
|
from .langhelpers import (
|
||||||
|
unbound_method_to_callable as unbound_method_to_callable,
|
||||||
|
)
|
||||||
|
from .langhelpers import walk_subclasses as walk_subclasses
|
||||||
|
from .langhelpers import warn as warn
|
||||||
|
from .langhelpers import warn_exception as warn_exception
|
||||||
|
from .langhelpers import warn_limited as warn_limited
|
||||||
|
from .langhelpers import wrap_callable as wrap_callable
|
||||||
|
from .preloaded import preload_module as preload_module
|
||||||
|
from .typing import is_non_string_iterable as is_non_string_iterable
|
||||||
712
venv/Lib/site-packages/sqlalchemy/util/_collections.py
Normal file
712
venv/Lib/site-packages/sqlalchemy/util/_collections.py
Normal file
@@ -0,0 +1,712 @@
|
|||||||
|
# util/_collections.py
|
||||||
|
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
||||||
|
# <see AUTHORS file>
|
||||||
|
#
|
||||||
|
# This module is part of SQLAlchemy and is released under
|
||||||
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
|
# mypy: allow-untyped-defs, allow-untyped-calls
|
||||||
|
|
||||||
|
"""Collection classes and helpers."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import operator
|
||||||
|
import threading
|
||||||
|
import types
|
||||||
|
import typing
|
||||||
|
from typing import Any
|
||||||
|
from typing import Callable
|
||||||
|
from typing import cast
|
||||||
|
from typing import Container
|
||||||
|
from typing import Dict
|
||||||
|
from typing import FrozenSet
|
||||||
|
from typing import Generic
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import Iterator
|
||||||
|
from typing import List
|
||||||
|
from typing import Mapping
|
||||||
|
from typing import NoReturn
|
||||||
|
from typing import Optional
|
||||||
|
from typing import overload
|
||||||
|
from typing import Sequence
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import Union
|
||||||
|
from typing import ValuesView
|
||||||
|
import weakref
|
||||||
|
|
||||||
|
from ._has_cy import HAS_CYEXTENSION
|
||||||
|
from .typing import is_non_string_iterable
|
||||||
|
from .typing import Literal
|
||||||
|
from .typing import Protocol
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING or not HAS_CYEXTENSION:
|
||||||
|
from ._py_collections import immutabledict as immutabledict
|
||||||
|
from ._py_collections import IdentitySet as IdentitySet
|
||||||
|
from ._py_collections import ReadOnlyContainer as ReadOnlyContainer
|
||||||
|
from ._py_collections import ImmutableDictBase as ImmutableDictBase
|
||||||
|
from ._py_collections import OrderedSet as OrderedSet
|
||||||
|
from ._py_collections import unique_list as unique_list
|
||||||
|
else:
|
||||||
|
from sqlalchemy.cyextension.immutabledict import (
|
||||||
|
ReadOnlyContainer as ReadOnlyContainer,
|
||||||
|
)
|
||||||
|
from sqlalchemy.cyextension.immutabledict import (
|
||||||
|
ImmutableDictBase as ImmutableDictBase,
|
||||||
|
)
|
||||||
|
from sqlalchemy.cyextension.immutabledict import (
|
||||||
|
immutabledict as immutabledict,
|
||||||
|
)
|
||||||
|
from sqlalchemy.cyextension.collections import IdentitySet as IdentitySet
|
||||||
|
from sqlalchemy.cyextension.collections import OrderedSet as OrderedSet
|
||||||
|
from sqlalchemy.cyextension.collections import ( # noqa
|
||||||
|
unique_list as unique_list,
|
||||||
|
)
|
||||||
|
|
||||||
|
_T = TypeVar("_T", bound=Any)
|
||||||
|
_KT = TypeVar("_KT", bound=Any)
|
||||||
|
_VT = TypeVar("_VT", bound=Any)
|
||||||
|
_T_co = TypeVar("_T_co", covariant=True)
|
||||||
|
|
||||||
|
EMPTY_SET: FrozenSet[Any] = frozenset()
|
||||||
|
NONE_SET: FrozenSet[Any] = frozenset([None])
|
||||||
|
|
||||||
|
|
||||||
|
def merge_lists_w_ordering(a: List[Any], b: List[Any]) -> List[Any]:
|
||||||
|
"""merge two lists, maintaining ordering as much as possible.
|
||||||
|
|
||||||
|
this is to reconcile vars(cls) with cls.__annotations__.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
>>> a = ["__tablename__", "id", "x", "created_at"]
|
||||||
|
>>> b = ["id", "name", "data", "y", "created_at"]
|
||||||
|
>>> merge_lists_w_ordering(a, b)
|
||||||
|
['__tablename__', 'id', 'name', 'data', 'y', 'x', 'created_at']
|
||||||
|
|
||||||
|
This is not necessarily the ordering that things had on the class,
|
||||||
|
in this case the class is::
|
||||||
|
|
||||||
|
class User(Base):
|
||||||
|
__tablename__ = "users"
|
||||||
|
|
||||||
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
|
name: Mapped[str]
|
||||||
|
data: Mapped[Optional[str]]
|
||||||
|
x = Column(Integer)
|
||||||
|
y: Mapped[int]
|
||||||
|
created_at: Mapped[datetime.datetime] = mapped_column()
|
||||||
|
|
||||||
|
But things are *mostly* ordered.
|
||||||
|
|
||||||
|
The algorithm could also be done by creating a partial ordering for
|
||||||
|
all items in both lists and then using topological_sort(), but that
|
||||||
|
is too much overhead.
|
||||||
|
|
||||||
|
Background on how I came up with this is at:
|
||||||
|
https://gist.github.com/zzzeek/89de958cf0803d148e74861bd682ebae
|
||||||
|
|
||||||
|
"""
|
||||||
|
overlap = set(a).intersection(b)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
current, other = iter(a), iter(b)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for element in current:
|
||||||
|
if element in overlap:
|
||||||
|
overlap.discard(element)
|
||||||
|
other, current = current, other
|
||||||
|
break
|
||||||
|
|
||||||
|
result.append(element)
|
||||||
|
else:
|
||||||
|
result.extend(other)
|
||||||
|
break
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def coerce_to_immutabledict(d: Mapping[_KT, _VT]) -> immutabledict[_KT, _VT]:
|
||||||
|
if not d:
|
||||||
|
return EMPTY_DICT
|
||||||
|
elif isinstance(d, immutabledict):
|
||||||
|
return d
|
||||||
|
else:
|
||||||
|
return immutabledict(d)
|
||||||
|
|
||||||
|
|
||||||
|
EMPTY_DICT: immutabledict[Any, Any] = immutabledict()
|
||||||
|
|
||||||
|
|
||||||
|
class FacadeDict(ImmutableDictBase[_KT, _VT]):
|
||||||
|
"""A dictionary that is not publicly mutable."""
|
||||||
|
|
||||||
|
def __new__(cls, *args: Any) -> FacadeDict[Any, Any]:
|
||||||
|
new = ImmutableDictBase.__new__(cls)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def copy(self) -> NoReturn:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"an immutabledict shouldn't need to be copied. use dict(d) "
|
||||||
|
"if you need a mutable dictionary."
|
||||||
|
)
|
||||||
|
|
||||||
|
def __reduce__(self) -> Any:
|
||||||
|
return FacadeDict, (dict(self),)
|
||||||
|
|
||||||
|
def _insert_item(self, key: _KT, value: _VT) -> None:
|
||||||
|
"""insert an item into the dictionary directly."""
|
||||||
|
dict.__setitem__(self, key, value)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "FacadeDict(%s)" % dict.__repr__(self)
|
||||||
|
|
||||||
|
|
||||||
|
_DT = TypeVar("_DT", bound=Any)
|
||||||
|
|
||||||
|
_F = TypeVar("_F", bound=Any)
|
||||||
|
|
||||||
|
|
||||||
|
class Properties(Generic[_T]):
|
||||||
|
"""Provide a __getattr__/__setattr__ interface over a dict."""
|
||||||
|
|
||||||
|
__slots__ = ("_data",)
|
||||||
|
|
||||||
|
_data: Dict[str, _T]
|
||||||
|
|
||||||
|
def __init__(self, data: Dict[str, _T]):
|
||||||
|
object.__setattr__(self, "_data", data)
|
||||||
|
|
||||||
|
def __len__(self) -> int:
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[_T]:
|
||||||
|
return iter(list(self._data.values()))
|
||||||
|
|
||||||
|
def __dir__(self) -> List[str]:
|
||||||
|
return dir(super()) + [str(k) for k in self._data.keys()]
|
||||||
|
|
||||||
|
def __add__(self, other: Properties[_F]) -> List[Union[_T, _F]]:
|
||||||
|
return list(self) + list(other)
|
||||||
|
|
||||||
|
def __setitem__(self, key: str, obj: _T) -> None:
|
||||||
|
self._data[key] = obj
|
||||||
|
|
||||||
|
def __getitem__(self, key: str) -> _T:
|
||||||
|
return self._data[key]
|
||||||
|
|
||||||
|
def __delitem__(self, key: str) -> None:
|
||||||
|
del self._data[key]
|
||||||
|
|
||||||
|
def __setattr__(self, key: str, obj: _T) -> None:
|
||||||
|
self._data[key] = obj
|
||||||
|
|
||||||
|
def __getstate__(self) -> Dict[str, Any]:
|
||||||
|
return {"_data": self._data}
|
||||||
|
|
||||||
|
def __setstate__(self, state: Dict[str, Any]) -> None:
|
||||||
|
object.__setattr__(self, "_data", state["_data"])
|
||||||
|
|
||||||
|
def __getattr__(self, key: str) -> _T:
|
||||||
|
try:
|
||||||
|
return self._data[key]
|
||||||
|
except KeyError:
|
||||||
|
raise AttributeError(key)
|
||||||
|
|
||||||
|
def __contains__(self, key: str) -> bool:
|
||||||
|
return key in self._data
|
||||||
|
|
||||||
|
def as_readonly(self) -> ReadOnlyProperties[_T]:
|
||||||
|
"""Return an immutable proxy for this :class:`.Properties`."""
|
||||||
|
|
||||||
|
return ReadOnlyProperties(self._data)
|
||||||
|
|
||||||
|
def update(self, value: Dict[str, _T]) -> None:
|
||||||
|
self._data.update(value)
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def get(self, key: str) -> Optional[_T]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def get(self, key: str, default: Union[_DT, _T]) -> Union[_DT, _T]: ...
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self, key: str, default: Optional[Union[_DT, _T]] = None
|
||||||
|
) -> Optional[Union[_T, _DT]]:
|
||||||
|
if key in self:
|
||||||
|
return self[key]
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
def keys(self) -> List[str]:
|
||||||
|
return list(self._data)
|
||||||
|
|
||||||
|
def values(self) -> List[_T]:
|
||||||
|
return list(self._data.values())
|
||||||
|
|
||||||
|
def items(self) -> List[Tuple[str, _T]]:
|
||||||
|
return list(self._data.items())
|
||||||
|
|
||||||
|
def has_key(self, key: str) -> bool:
|
||||||
|
return key in self._data
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
self._data.clear()
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedProperties(Properties[_T]):
|
||||||
|
"""Provide a __getattr__/__setattr__ interface with an OrderedDict
|
||||||
|
as backing store."""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
Properties.__init__(self, OrderedDict())
|
||||||
|
|
||||||
|
|
||||||
|
class ReadOnlyProperties(ReadOnlyContainer, Properties[_T]):
|
||||||
|
"""Provide immutable dict/object attribute to an underlying dictionary."""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
|
||||||
|
def _ordered_dictionary_sort(d, key=None):
|
||||||
|
"""Sort an OrderedDict in-place."""
|
||||||
|
|
||||||
|
items = [(k, d[k]) for k in sorted(d, key=key)]
|
||||||
|
|
||||||
|
d.clear()
|
||||||
|
|
||||||
|
d.update(items)
|
||||||
|
|
||||||
|
|
||||||
|
OrderedDict = dict
|
||||||
|
sort_dictionary = _ordered_dictionary_sort
|
||||||
|
|
||||||
|
|
||||||
|
class WeakSequence(Sequence[_T]):
|
||||||
|
def __init__(self, __elements: Sequence[_T] = ()):
|
||||||
|
# adapted from weakref.WeakKeyDictionary, prevent reference
|
||||||
|
# cycles in the collection itself
|
||||||
|
def _remove(item, selfref=weakref.ref(self)):
|
||||||
|
self = selfref()
|
||||||
|
if self is not None:
|
||||||
|
self._storage.remove(item)
|
||||||
|
|
||||||
|
self._remove = _remove
|
||||||
|
self._storage = [
|
||||||
|
weakref.ref(element, _remove) for element in __elements
|
||||||
|
]
|
||||||
|
|
||||||
|
def append(self, item):
|
||||||
|
self._storage.append(weakref.ref(item, self._remove))
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._storage)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (
|
||||||
|
obj for obj in (ref() for ref in self._storage) if obj is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return self._storage[index]()
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedIdentitySet(IdentitySet):
|
||||||
|
def __init__(self, iterable: Optional[Iterable[Any]] = None):
|
||||||
|
IdentitySet.__init__(self)
|
||||||
|
self._members = OrderedDict()
|
||||||
|
if iterable:
|
||||||
|
for o in iterable:
|
||||||
|
self.add(o)
|
||||||
|
|
||||||
|
|
||||||
|
class PopulateDict(Dict[_KT, _VT]):
|
||||||
|
"""A dict which populates missing values via a creation function.
|
||||||
|
|
||||||
|
Note the creation function takes a key, unlike
|
||||||
|
collections.defaultdict.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, creator: Callable[[_KT], _VT]):
|
||||||
|
self.creator = creator
|
||||||
|
|
||||||
|
def __missing__(self, key: Any) -> Any:
|
||||||
|
self[key] = val = self.creator(key)
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
class WeakPopulateDict(Dict[_KT, _VT]):
|
||||||
|
"""Like PopulateDict, but assumes a self + a method and does not create
|
||||||
|
a reference cycle.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, creator_method: types.MethodType):
|
||||||
|
self.creator = creator_method.__func__
|
||||||
|
weakself = creator_method.__self__
|
||||||
|
self.weakself = weakref.ref(weakself)
|
||||||
|
|
||||||
|
def __missing__(self, key: Any) -> Any:
|
||||||
|
self[key] = val = self.creator(self.weakself(), key)
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
# Define collections that are capable of storing
|
||||||
|
# ColumnElement objects as hashable keys/elements.
|
||||||
|
# At this point, these are mostly historical, things
|
||||||
|
# used to be more complicated.
|
||||||
|
column_set = set
|
||||||
|
column_dict = dict
|
||||||
|
ordered_column_set = OrderedSet
|
||||||
|
|
||||||
|
|
||||||
|
class UniqueAppender(Generic[_T]):
|
||||||
|
"""Appends items to a collection ensuring uniqueness.
|
||||||
|
|
||||||
|
Additional appends() of the same object are ignored. Membership is
|
||||||
|
determined by identity (``is a``) not equality (``==``).
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = "data", "_data_appender", "_unique"
|
||||||
|
|
||||||
|
data: Union[Iterable[_T], Set[_T], List[_T]]
|
||||||
|
_data_appender: Callable[[_T], None]
|
||||||
|
_unique: Dict[int, Literal[True]]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
data: Union[Iterable[_T], Set[_T], List[_T]],
|
||||||
|
via: Optional[str] = None,
|
||||||
|
):
|
||||||
|
self.data = data
|
||||||
|
self._unique = {}
|
||||||
|
if via:
|
||||||
|
self._data_appender = getattr(data, via)
|
||||||
|
elif hasattr(data, "append"):
|
||||||
|
self._data_appender = cast("List[_T]", data).append
|
||||||
|
elif hasattr(data, "add"):
|
||||||
|
self._data_appender = cast("Set[_T]", data).add
|
||||||
|
|
||||||
|
def append(self, item: _T) -> None:
|
||||||
|
id_ = id(item)
|
||||||
|
if id_ not in self._unique:
|
||||||
|
self._data_appender(item)
|
||||||
|
self._unique[id_] = True
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[_T]:
|
||||||
|
return iter(self.data)
|
||||||
|
|
||||||
|
|
||||||
|
def coerce_generator_arg(arg: Any) -> List[Any]:
|
||||||
|
if len(arg) == 1 and isinstance(arg[0], types.GeneratorType):
|
||||||
|
return list(arg[0])
|
||||||
|
else:
|
||||||
|
return cast("List[Any]", arg)
|
||||||
|
|
||||||
|
|
||||||
|
def to_list(x: Any, default: Optional[List[Any]] = None) -> List[Any]:
|
||||||
|
if x is None:
|
||||||
|
return default # type: ignore
|
||||||
|
if not is_non_string_iterable(x):
|
||||||
|
return [x]
|
||||||
|
elif isinstance(x, list):
|
||||||
|
return x
|
||||||
|
else:
|
||||||
|
return list(x)
|
||||||
|
|
||||||
|
|
||||||
|
def has_intersection(set_: Container[Any], iterable: Iterable[Any]) -> bool:
|
||||||
|
r"""return True if any items of set\_ are present in iterable.
|
||||||
|
|
||||||
|
Goes through special effort to ensure __hash__ is not called
|
||||||
|
on items in iterable that don't support it.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return any(i in set_ for i in iterable if i.__hash__)
|
||||||
|
|
||||||
|
|
||||||
|
def to_set(x):
|
||||||
|
if x is None:
|
||||||
|
return set()
|
||||||
|
if not isinstance(x, set):
|
||||||
|
return set(to_list(x))
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def to_column_set(x: Any) -> Set[Any]:
|
||||||
|
if x is None:
|
||||||
|
return column_set()
|
||||||
|
if not isinstance(x, column_set):
|
||||||
|
return column_set(to_list(x))
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def update_copy(
|
||||||
|
d: Dict[Any, Any], _new: Optional[Dict[Any, Any]] = None, **kw: Any
|
||||||
|
) -> Dict[Any, Any]:
|
||||||
|
"""Copy the given dict and update with the given values."""
|
||||||
|
|
||||||
|
d = d.copy()
|
||||||
|
if _new:
|
||||||
|
d.update(_new)
|
||||||
|
d.update(**kw)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def flatten_iterator(x: Iterable[_T]) -> Iterator[_T]:
|
||||||
|
"""Given an iterator of which further sub-elements may also be
|
||||||
|
iterators, flatten the sub-elements into a single iterator.
|
||||||
|
|
||||||
|
"""
|
||||||
|
elem: _T
|
||||||
|
for elem in x:
|
||||||
|
if not isinstance(elem, str) and hasattr(elem, "__iter__"):
|
||||||
|
yield from flatten_iterator(elem)
|
||||||
|
else:
|
||||||
|
yield elem
|
||||||
|
|
||||||
|
|
||||||
|
class LRUCache(typing.MutableMapping[_KT, _VT]):
|
||||||
|
"""Dictionary with 'squishy' removal of least
|
||||||
|
recently used items.
|
||||||
|
|
||||||
|
Note that either get() or [] should be used here, but
|
||||||
|
generally its not safe to do an "in" check first as the dictionary
|
||||||
|
can change subsequent to that call.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = (
|
||||||
|
"capacity",
|
||||||
|
"threshold",
|
||||||
|
"size_alert",
|
||||||
|
"_data",
|
||||||
|
"_counter",
|
||||||
|
"_mutex",
|
||||||
|
)
|
||||||
|
|
||||||
|
capacity: int
|
||||||
|
threshold: float
|
||||||
|
size_alert: Optional[Callable[[LRUCache[_KT, _VT]], None]]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
capacity: int = 100,
|
||||||
|
threshold: float = 0.5,
|
||||||
|
size_alert: Optional[Callable[..., None]] = None,
|
||||||
|
):
|
||||||
|
self.capacity = capacity
|
||||||
|
self.threshold = threshold
|
||||||
|
self.size_alert = size_alert
|
||||||
|
self._counter = 0
|
||||||
|
self._mutex = threading.Lock()
|
||||||
|
self._data: Dict[_KT, Tuple[_KT, _VT, List[int]]] = {}
|
||||||
|
|
||||||
|
def _inc_counter(self):
|
||||||
|
self._counter += 1
|
||||||
|
return self._counter
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def get(self, key: _KT) -> Optional[_VT]: ...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def get(self, key: _KT, default: Union[_VT, _T]) -> Union[_VT, _T]: ...
|
||||||
|
|
||||||
|
def get(
|
||||||
|
self, key: _KT, default: Optional[Union[_VT, _T]] = None
|
||||||
|
) -> Optional[Union[_VT, _T]]:
|
||||||
|
item = self._data.get(key)
|
||||||
|
if item is not None:
|
||||||
|
item[2][0] = self._inc_counter()
|
||||||
|
return item[1]
|
||||||
|
else:
|
||||||
|
return default
|
||||||
|
|
||||||
|
def __getitem__(self, key: _KT) -> _VT:
|
||||||
|
item = self._data[key]
|
||||||
|
item[2][0] = self._inc_counter()
|
||||||
|
return item[1]
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[_KT]:
|
||||||
|
return iter(self._data)
|
||||||
|
|
||||||
|
def __len__(self) -> int:
|
||||||
|
return len(self._data)
|
||||||
|
|
||||||
|
def values(self) -> ValuesView[_VT]:
|
||||||
|
return typing.ValuesView({k: i[1] for k, i in self._data.items()})
|
||||||
|
|
||||||
|
def __setitem__(self, key: _KT, value: _VT) -> None:
|
||||||
|
self._data[key] = (key, value, [self._inc_counter()])
|
||||||
|
self._manage_size()
|
||||||
|
|
||||||
|
def __delitem__(self, __v: _KT) -> None:
|
||||||
|
del self._data[__v]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size_threshold(self) -> float:
|
||||||
|
return self.capacity + self.capacity * self.threshold
|
||||||
|
|
||||||
|
def _manage_size(self) -> None:
|
||||||
|
if not self._mutex.acquire(False):
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
size_alert = bool(self.size_alert)
|
||||||
|
while len(self) > self.capacity + self.capacity * self.threshold:
|
||||||
|
if size_alert:
|
||||||
|
size_alert = False
|
||||||
|
self.size_alert(self) # type: ignore
|
||||||
|
by_counter = sorted(
|
||||||
|
self._data.values(),
|
||||||
|
key=operator.itemgetter(2),
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
for item in by_counter[self.capacity :]:
|
||||||
|
try:
|
||||||
|
del self._data[item[0]]
|
||||||
|
except KeyError:
|
||||||
|
# deleted elsewhere; skip
|
||||||
|
continue
|
||||||
|
finally:
|
||||||
|
self._mutex.release()
|
||||||
|
|
||||||
|
|
||||||
|
class _CreateFuncType(Protocol[_T_co]):
|
||||||
|
def __call__(self) -> _T_co: ...
|
||||||
|
|
||||||
|
|
||||||
|
class _ScopeFuncType(Protocol):
|
||||||
|
def __call__(self) -> Any: ...
|
||||||
|
|
||||||
|
|
||||||
|
class ScopedRegistry(Generic[_T]):
|
||||||
|
"""A Registry that can store one or multiple instances of a single
|
||||||
|
class on the basis of a "scope" function.
|
||||||
|
|
||||||
|
The object implements ``__call__`` as the "getter", so by
|
||||||
|
calling ``myregistry()`` the contained object is returned
|
||||||
|
for the current scope.
|
||||||
|
|
||||||
|
:param createfunc:
|
||||||
|
a callable that returns a new object to be placed in the registry
|
||||||
|
|
||||||
|
:param scopefunc:
|
||||||
|
a callable that will return a key to store/retrieve an object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = "createfunc", "scopefunc", "registry"
|
||||||
|
|
||||||
|
createfunc: _CreateFuncType[_T]
|
||||||
|
scopefunc: _ScopeFuncType
|
||||||
|
registry: Any
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, createfunc: Callable[[], _T], scopefunc: Callable[[], Any]
|
||||||
|
):
|
||||||
|
"""Construct a new :class:`.ScopedRegistry`.
|
||||||
|
|
||||||
|
:param createfunc: A creation function that will generate
|
||||||
|
a new value for the current scope, if none is present.
|
||||||
|
|
||||||
|
:param scopefunc: A function that returns a hashable
|
||||||
|
token representing the current scope (such as, current
|
||||||
|
thread identifier).
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.createfunc = createfunc
|
||||||
|
self.scopefunc = scopefunc
|
||||||
|
self.registry = {}
|
||||||
|
|
||||||
|
def __call__(self) -> _T:
|
||||||
|
key = self.scopefunc()
|
||||||
|
try:
|
||||||
|
return self.registry[key] # type: ignore[no-any-return]
|
||||||
|
except KeyError:
|
||||||
|
return self.registry.setdefault(key, self.createfunc()) # type: ignore[no-any-return] # noqa: E501
|
||||||
|
|
||||||
|
def has(self) -> bool:
|
||||||
|
"""Return True if an object is present in the current scope."""
|
||||||
|
|
||||||
|
return self.scopefunc() in self.registry
|
||||||
|
|
||||||
|
def set(self, obj: _T) -> None:
|
||||||
|
"""Set the value for the current scope."""
|
||||||
|
|
||||||
|
self.registry[self.scopefunc()] = obj
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
"""Clear the current scope, if any."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
del self.registry[self.scopefunc()]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadLocalRegistry(ScopedRegistry[_T]):
|
||||||
|
"""A :class:`.ScopedRegistry` that uses a ``threading.local()``
|
||||||
|
variable for storage.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, createfunc: Callable[[], _T]):
|
||||||
|
self.createfunc = createfunc
|
||||||
|
self.registry = threading.local()
|
||||||
|
|
||||||
|
def __call__(self) -> _T:
|
||||||
|
try:
|
||||||
|
return self.registry.value # type: ignore[no-any-return]
|
||||||
|
except AttributeError:
|
||||||
|
val = self.registry.value = self.createfunc()
|
||||||
|
return val
|
||||||
|
|
||||||
|
def has(self) -> bool:
|
||||||
|
return hasattr(self.registry, "value")
|
||||||
|
|
||||||
|
def set(self, obj: _T) -> None:
|
||||||
|
self.registry.value = obj
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
try:
|
||||||
|
del self.registry.value
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def has_dupes(sequence, target):
|
||||||
|
"""Given a sequence and search object, return True if there's more
|
||||||
|
than one, False if zero or one of them.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
# compare to .index version below, this version introduces less function
|
||||||
|
# overhead and is usually the same speed. At 15000 items (way bigger than
|
||||||
|
# a relationship-bound collection in memory usually is) it begins to
|
||||||
|
# fall behind the other version only by microseconds.
|
||||||
|
c = 0
|
||||||
|
for item in sequence:
|
||||||
|
if item is target:
|
||||||
|
c += 1
|
||||||
|
if c > 1:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# .index version. the two __contains__ calls as well
|
||||||
|
# as .index() and isinstance() slow this down.
|
||||||
|
# def has_dupes(sequence, target):
|
||||||
|
# if target not in sequence:
|
||||||
|
# return False
|
||||||
|
# elif not isinstance(sequence, collections_abc.Sequence):
|
||||||
|
# return False
|
||||||
|
#
|
||||||
|
# idx = sequence.index(target)
|
||||||
|
# return target in sequence[idx + 1:]
|
||||||
288
venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py
Normal file
288
venv/Lib/site-packages/sqlalchemy/util/_concurrency_py3k.py
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
# util/_concurrency_py3k.py
|
||||||
|
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
||||||
|
# <see AUTHORS file>
|
||||||
|
#
|
||||||
|
# This module is part of SQLAlchemy and is released under
|
||||||
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
|
# mypy: allow-untyped-defs, allow-untyped-calls
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from contextvars import Context
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
from typing import Any
|
||||||
|
from typing import Awaitable
|
||||||
|
from typing import Callable
|
||||||
|
from typing import Coroutine
|
||||||
|
from typing import Optional
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from .langhelpers import memoized_property
|
||||||
|
from .. import exc
|
||||||
|
from ..util import py311
|
||||||
|
from ..util.typing import Literal
|
||||||
|
from ..util.typing import Protocol
|
||||||
|
from ..util.typing import Self
|
||||||
|
from ..util.typing import TypeGuard
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
|
if typing.TYPE_CHECKING:
|
||||||
|
|
||||||
|
class greenlet(Protocol):
|
||||||
|
dead: bool
|
||||||
|
gr_context: Optional[Context]
|
||||||
|
|
||||||
|
def __init__(self, fn: Callable[..., Any], driver: greenlet): ...
|
||||||
|
|
||||||
|
def throw(self, *arg: Any) -> Any:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def switch(self, value: Any) -> Any:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getcurrent() -> greenlet: ...
|
||||||
|
|
||||||
|
else:
|
||||||
|
from greenlet import getcurrent
|
||||||
|
from greenlet import greenlet
|
||||||
|
|
||||||
|
|
||||||
|
# If greenlet.gr_context is present in current version of greenlet,
|
||||||
|
# it will be set with the current context on creation.
|
||||||
|
# Refs: https://github.com/python-greenlet/greenlet/pull/198
|
||||||
|
_has_gr_context = hasattr(getcurrent(), "gr_context")
|
||||||
|
|
||||||
|
|
||||||
|
def is_exit_exception(e: BaseException) -> bool:
|
||||||
|
# note asyncio.CancelledError is already BaseException
|
||||||
|
# so was an exit exception in any case
|
||||||
|
return not isinstance(e, Exception) or isinstance(
|
||||||
|
e, (asyncio.TimeoutError, asyncio.CancelledError)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# implementation based on snaury gist at
|
||||||
|
# https://gist.github.com/snaury/202bf4f22c41ca34e56297bae5f33fef
|
||||||
|
# Issue for context: https://github.com/python-greenlet/greenlet/issues/173
|
||||||
|
|
||||||
|
|
||||||
|
class _AsyncIoGreenlet(greenlet):
|
||||||
|
dead: bool
|
||||||
|
|
||||||
|
__sqlalchemy_greenlet_provider__ = True
|
||||||
|
|
||||||
|
def __init__(self, fn: Callable[..., Any], driver: greenlet):
|
||||||
|
greenlet.__init__(self, fn, driver)
|
||||||
|
if _has_gr_context:
|
||||||
|
self.gr_context = driver.gr_context
|
||||||
|
|
||||||
|
|
||||||
|
_T_co = TypeVar("_T_co", covariant=True)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
def iscoroutine(
|
||||||
|
awaitable: Awaitable[_T_co],
|
||||||
|
) -> TypeGuard[Coroutine[Any, Any, _T_co]]: ...
|
||||||
|
|
||||||
|
else:
|
||||||
|
iscoroutine = asyncio.iscoroutine
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_cancel_awaitable(awaitable: Awaitable[Any]) -> None:
|
||||||
|
# https://docs.python.org/3/reference/datamodel.html#coroutine.close
|
||||||
|
|
||||||
|
if iscoroutine(awaitable):
|
||||||
|
awaitable.close()
|
||||||
|
|
||||||
|
|
||||||
|
def in_greenlet() -> bool:
|
||||||
|
current = getcurrent()
|
||||||
|
return getattr(current, "__sqlalchemy_greenlet_provider__", False)
|
||||||
|
|
||||||
|
|
||||||
|
def await_only(awaitable: Awaitable[_T]) -> _T:
|
||||||
|
"""Awaits an async function in a sync method.
|
||||||
|
|
||||||
|
The sync method must be inside a :func:`greenlet_spawn` context.
|
||||||
|
:func:`await_only` calls cannot be nested.
|
||||||
|
|
||||||
|
:param awaitable: The coroutine to call.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# this is called in the context greenlet while running fn
|
||||||
|
current = getcurrent()
|
||||||
|
if not getattr(current, "__sqlalchemy_greenlet_provider__", False):
|
||||||
|
_safe_cancel_awaitable(awaitable)
|
||||||
|
|
||||||
|
raise exc.MissingGreenlet(
|
||||||
|
"greenlet_spawn has not been called; can't call await_only() "
|
||||||
|
"here. Was IO attempted in an unexpected place?"
|
||||||
|
)
|
||||||
|
|
||||||
|
# returns the control to the driver greenlet passing it
|
||||||
|
# a coroutine to run. Once the awaitable is done, the driver greenlet
|
||||||
|
# switches back to this greenlet with the result of awaitable that is
|
||||||
|
# then returned to the caller (or raised as error)
|
||||||
|
return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
|
||||||
|
|
||||||
|
|
||||||
|
def await_fallback(awaitable: Awaitable[_T]) -> _T:
|
||||||
|
"""Awaits an async function in a sync method.
|
||||||
|
|
||||||
|
The sync method must be inside a :func:`greenlet_spawn` context.
|
||||||
|
:func:`await_fallback` calls cannot be nested.
|
||||||
|
|
||||||
|
:param awaitable: The coroutine to call.
|
||||||
|
|
||||||
|
.. deprecated:: 2.0.24 The ``await_fallback()`` function will be removed
|
||||||
|
in SQLAlchemy 2.1. Use :func:`_util.await_only` instead, running the
|
||||||
|
function / program / etc. within a top-level greenlet that is set up
|
||||||
|
using :func:`_util.greenlet_spawn`.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# this is called in the context greenlet while running fn
|
||||||
|
current = getcurrent()
|
||||||
|
if not getattr(current, "__sqlalchemy_greenlet_provider__", False):
|
||||||
|
loop = get_event_loop()
|
||||||
|
if loop.is_running():
|
||||||
|
_safe_cancel_awaitable(awaitable)
|
||||||
|
|
||||||
|
raise exc.MissingGreenlet(
|
||||||
|
"greenlet_spawn has not been called and asyncio event "
|
||||||
|
"loop is already running; can't call await_fallback() here. "
|
||||||
|
"Was IO attempted in an unexpected place?"
|
||||||
|
)
|
||||||
|
return loop.run_until_complete(awaitable)
|
||||||
|
|
||||||
|
return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
|
||||||
|
|
||||||
|
|
||||||
|
async def greenlet_spawn(
|
||||||
|
fn: Callable[..., _T],
|
||||||
|
*args: Any,
|
||||||
|
_require_await: bool = False,
|
||||||
|
**kwargs: Any,
|
||||||
|
) -> _T:
|
||||||
|
"""Runs a sync function ``fn`` in a new greenlet.
|
||||||
|
|
||||||
|
The sync function can then use :func:`await_only` to wait for async
|
||||||
|
functions.
|
||||||
|
|
||||||
|
:param fn: The sync callable to call.
|
||||||
|
:param \\*args: Positional arguments to pass to the ``fn`` callable.
|
||||||
|
:param \\*\\*kwargs: Keyword arguments to pass to the ``fn`` callable.
|
||||||
|
"""
|
||||||
|
|
||||||
|
result: Any
|
||||||
|
context = _AsyncIoGreenlet(fn, getcurrent())
|
||||||
|
# runs the function synchronously in gl greenlet. If the execution
|
||||||
|
# is interrupted by await_only, context is not dead and result is a
|
||||||
|
# coroutine to wait. If the context is dead the function has
|
||||||
|
# returned, and its result can be returned.
|
||||||
|
switch_occurred = False
|
||||||
|
result = context.switch(*args, **kwargs)
|
||||||
|
while not context.dead:
|
||||||
|
switch_occurred = True
|
||||||
|
try:
|
||||||
|
# wait for a coroutine from await_only and then return its
|
||||||
|
# result back to it.
|
||||||
|
value = await result
|
||||||
|
except BaseException:
|
||||||
|
# this allows an exception to be raised within
|
||||||
|
# the moderated greenlet so that it can continue
|
||||||
|
# its expected flow.
|
||||||
|
result = context.throw(*sys.exc_info())
|
||||||
|
else:
|
||||||
|
result = context.switch(value)
|
||||||
|
|
||||||
|
if _require_await and not switch_occurred:
|
||||||
|
raise exc.AwaitRequired(
|
||||||
|
"The current operation required an async execution but none was "
|
||||||
|
"detected. This will usually happen when using a non compatible "
|
||||||
|
"DBAPI driver. Please ensure that an async DBAPI is used."
|
||||||
|
)
|
||||||
|
return result # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
|
||||||
|
class AsyncAdaptedLock:
|
||||||
|
@memoized_property
|
||||||
|
def mutex(self) -> asyncio.Lock:
|
||||||
|
# there should not be a race here for coroutines creating the
|
||||||
|
# new lock as we are not using await, so therefore no concurrency
|
||||||
|
return asyncio.Lock()
|
||||||
|
|
||||||
|
def __enter__(self) -> bool:
|
||||||
|
# await is used to acquire the lock only after the first calling
|
||||||
|
# coroutine has created the mutex.
|
||||||
|
return await_fallback(self.mutex.acquire())
|
||||||
|
|
||||||
|
def __exit__(self, *arg: Any, **kw: Any) -> None:
|
||||||
|
self.mutex.release()
|
||||||
|
|
||||||
|
|
||||||
|
def get_event_loop() -> asyncio.AbstractEventLoop:
|
||||||
|
"""vendor asyncio.get_event_loop() for python 3.7 and above.
|
||||||
|
|
||||||
|
Python 3.10 deprecates get_event_loop() as a standalone.
|
||||||
|
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return asyncio.get_running_loop()
|
||||||
|
except RuntimeError:
|
||||||
|
# avoid "During handling of the above exception, another exception..."
|
||||||
|
pass
|
||||||
|
return asyncio.get_event_loop_policy().get_event_loop()
|
||||||
|
|
||||||
|
|
||||||
|
if not TYPE_CHECKING and py311:
|
||||||
|
_Runner = asyncio.Runner
|
||||||
|
else:
|
||||||
|
|
||||||
|
class _Runner:
|
||||||
|
"""Runner implementation for test only"""
|
||||||
|
|
||||||
|
_loop: Union[None, asyncio.AbstractEventLoop, Literal[False]]
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._loop = None
|
||||||
|
|
||||||
|
def __enter__(self) -> Self:
|
||||||
|
self._lazy_init()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
if self._loop:
|
||||||
|
try:
|
||||||
|
self._loop.run_until_complete(
|
||||||
|
self._loop.shutdown_asyncgens()
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
self._loop.close()
|
||||||
|
self._loop = False
|
||||||
|
|
||||||
|
def get_loop(self) -> asyncio.AbstractEventLoop:
|
||||||
|
"""Return embedded event loop."""
|
||||||
|
self._lazy_init()
|
||||||
|
assert self._loop
|
||||||
|
return self._loop
|
||||||
|
|
||||||
|
def run(self, coro: Coroutine[Any, Any, _T]) -> _T:
|
||||||
|
self._lazy_init()
|
||||||
|
assert self._loop
|
||||||
|
return self._loop.run_until_complete(coro)
|
||||||
|
|
||||||
|
def _lazy_init(self) -> None:
|
||||||
|
if self._loop is False:
|
||||||
|
raise RuntimeError("Runner is closed")
|
||||||
|
if self._loop is None:
|
||||||
|
self._loop = asyncio.new_event_loop()
|
||||||
40
venv/Lib/site-packages/sqlalchemy/util/_has_cy.py
Normal file
40
venv/Lib/site-packages/sqlalchemy/util/_has_cy.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# util/_has_cy.py
|
||||||
|
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
||||||
|
# <see AUTHORS file>
|
||||||
|
#
|
||||||
|
# This module is part of SQLAlchemy and is released under
|
||||||
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
|
# mypy: ignore-errors
|
||||||
|
|
||||||
|
import os
|
||||||
|
import typing
|
||||||
|
|
||||||
|
|
||||||
|
def _import_cy_extensions():
|
||||||
|
# all cython extension extension modules are treated as optional by the
|
||||||
|
# setup, so to ensure that all are compiled, all should be imported here
|
||||||
|
from ..cyextension import collections
|
||||||
|
from ..cyextension import immutabledict
|
||||||
|
from ..cyextension import processors
|
||||||
|
from ..cyextension import resultproxy
|
||||||
|
from ..cyextension import util
|
||||||
|
|
||||||
|
return (collections, immutabledict, processors, resultproxy, util)
|
||||||
|
|
||||||
|
|
||||||
|
_CYEXTENSION_MSG: str
|
||||||
|
if not typing.TYPE_CHECKING:
|
||||||
|
if os.environ.get("DISABLE_SQLALCHEMY_CEXT_RUNTIME"):
|
||||||
|
HAS_CYEXTENSION = False
|
||||||
|
_CYEXTENSION_MSG = "DISABLE_SQLALCHEMY_CEXT_RUNTIME is set"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
_import_cy_extensions()
|
||||||
|
except ImportError as err:
|
||||||
|
HAS_CYEXTENSION = False
|
||||||
|
_CYEXTENSION_MSG = str(err)
|
||||||
|
else:
|
||||||
|
_CYEXTENSION_MSG = "Loaded"
|
||||||
|
HAS_CYEXTENSION = True
|
||||||
|
else:
|
||||||
|
HAS_CYEXTENSION = False
|
||||||
541
venv/Lib/site-packages/sqlalchemy/util/_py_collections.py
Normal file
541
venv/Lib/site-packages/sqlalchemy/util/_py_collections.py
Normal file
@@ -0,0 +1,541 @@
|
|||||||
|
# util/_py_collections.py
|
||||||
|
# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
|
||||||
|
# <see AUTHORS file>
|
||||||
|
#
|
||||||
|
# This module is part of SQLAlchemy and is released under
|
||||||
|
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||||
|
# mypy: allow-untyped-defs, allow-untyped-calls
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from itertools import filterfalse
|
||||||
|
from typing import AbstractSet
|
||||||
|
from typing import Any
|
||||||
|
from typing import Callable
|
||||||
|
from typing import cast
|
||||||
|
from typing import Collection
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Iterable
|
||||||
|
from typing import Iterator
|
||||||
|
from typing import List
|
||||||
|
from typing import Mapping
|
||||||
|
from typing import NoReturn
|
||||||
|
from typing import Optional
|
||||||
|
from typing import Set
|
||||||
|
from typing import Tuple
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
from typing import TypeVar
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from ..util.typing import Self
|
||||||
|
|
||||||
|
_T = TypeVar("_T", bound=Any)
|
||||||
|
_S = TypeVar("_S", bound=Any)
|
||||||
|
_KT = TypeVar("_KT", bound=Any)
|
||||||
|
_VT = TypeVar("_VT", bound=Any)
|
||||||
|
|
||||||
|
|
||||||
|
class ReadOnlyContainer:
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def _readonly(self, *arg: Any, **kw: Any) -> NoReturn:
|
||||||
|
raise TypeError(
|
||||||
|
"%s object is immutable and/or readonly" % self.__class__.__name__
|
||||||
|
)
|
||||||
|
|
||||||
|
def _immutable(self, *arg: Any, **kw: Any) -> NoReturn:
|
||||||
|
raise TypeError("%s object is immutable" % self.__class__.__name__)
|
||||||
|
|
||||||
|
def __delitem__(self, key: Any) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def __setitem__(self, key: Any, value: Any) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def __setattr__(self, key: str, value: Any) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
|
||||||
|
class ImmutableDictBase(ReadOnlyContainer, Dict[_KT, _VT]):
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
|
||||||
|
def __new__(cls, *args: Any) -> Self: ...
|
||||||
|
|
||||||
|
def __init__(cls, *args: Any): ...
|
||||||
|
|
||||||
|
def _readonly(self, *arg: Any, **kw: Any) -> NoReturn:
|
||||||
|
self._immutable()
|
||||||
|
|
||||||
|
def clear(self) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def pop(self, key: Any, default: Optional[Any] = None) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def popitem(self) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def setdefault(self, key: Any, default: Optional[Any] = None) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def update(self, *arg: Any, **kw: Any) -> NoReturn:
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
|
||||||
|
class immutabledict(ImmutableDictBase[_KT, _VT]):
|
||||||
|
def __new__(cls, *args):
|
||||||
|
new = ImmutableDictBase.__new__(cls)
|
||||||
|
dict.__init__(new, *args)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self, *args: Union[Mapping[_KT, _VT], Iterable[Tuple[_KT, _VT]]]
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __reduce__(self):
|
||||||
|
return immutabledict, (dict(self),)
|
||||||
|
|
||||||
|
def union(
|
||||||
|
self, __d: Optional[Mapping[_KT, _VT]] = None
|
||||||
|
) -> immutabledict[_KT, _VT]:
|
||||||
|
if not __d:
|
||||||
|
return self
|
||||||
|
|
||||||
|
new = ImmutableDictBase.__new__(self.__class__)
|
||||||
|
dict.__init__(new, self)
|
||||||
|
dict.update(new, __d)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def _union_w_kw(
|
||||||
|
self, __d: Optional[Mapping[_KT, _VT]] = None, **kw: _VT
|
||||||
|
) -> immutabledict[_KT, _VT]:
|
||||||
|
# not sure if C version works correctly w/ this yet
|
||||||
|
if not __d and not kw:
|
||||||
|
return self
|
||||||
|
|
||||||
|
new = ImmutableDictBase.__new__(self.__class__)
|
||||||
|
dict.__init__(new, self)
|
||||||
|
if __d:
|
||||||
|
dict.update(new, __d)
|
||||||
|
dict.update(new, kw)
|
||||||
|
return new
|
||||||
|
|
||||||
|
def merge_with(
|
||||||
|
self, *dicts: Optional[Mapping[_KT, _VT]]
|
||||||
|
) -> immutabledict[_KT, _VT]:
|
||||||
|
new = None
|
||||||
|
for d in dicts:
|
||||||
|
if d:
|
||||||
|
if new is None:
|
||||||
|
new = ImmutableDictBase.__new__(self.__class__)
|
||||||
|
dict.__init__(new, self)
|
||||||
|
dict.update(new, d)
|
||||||
|
if new is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
return new
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "immutabledict(%s)" % dict.__repr__(self)
|
||||||
|
|
||||||
|
# PEP 584
|
||||||
|
def __ior__(self, __value: Any) -> NoReturn: # type: ignore
|
||||||
|
self._readonly()
|
||||||
|
|
||||||
|
def __or__( # type: ignore[override]
|
||||||
|
self, __value: Mapping[_KT, _VT]
|
||||||
|
) -> immutabledict[_KT, _VT]:
|
||||||
|
return immutabledict(
|
||||||
|
super().__or__(__value), # type: ignore[call-overload,operator,unused-ignore] # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
def __ror__( # type: ignore[override]
|
||||||
|
self, __value: Mapping[_KT, _VT]
|
||||||
|
) -> immutabledict[_KT, _VT]:
|
||||||
|
return immutabledict(
|
||||||
|
super().__ror__(__value), # type: ignore[call-overload,operator,unused-ignore] # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class OrderedSet(Set[_T]):
|
||||||
|
__slots__ = ("_list",)
|
||||||
|
|
||||||
|
_list: List[_T]
|
||||||
|
|
||||||
|
def __init__(self, d: Optional[Iterable[_T]] = None) -> None:
|
||||||
|
if d is not None:
|
||||||
|
self._list = unique_list(d)
|
||||||
|
super().update(self._list)
|
||||||
|
else:
|
||||||
|
self._list = []
|
||||||
|
|
||||||
|
def copy(self) -> OrderedSet[_T]:
|
||||||
|
cp = self.__class__()
|
||||||
|
cp._list = self._list.copy()
|
||||||
|
set.update(cp, cp._list)
|
||||||
|
return cp
|
||||||
|
|
||||||
|
def add(self, element: _T) -> None:
|
||||||
|
if element not in self:
|
||||||
|
self._list.append(element)
|
||||||
|
super().add(element)
|
||||||
|
|
||||||
|
def remove(self, element: _T) -> None:
|
||||||
|
super().remove(element)
|
||||||
|
self._list.remove(element)
|
||||||
|
|
||||||
|
def pop(self) -> _T:
|
||||||
|
try:
|
||||||
|
value = self._list.pop()
|
||||||
|
except IndexError:
|
||||||
|
raise KeyError("pop from an empty set") from None
|
||||||
|
super().remove(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def insert(self, pos: int, element: _T) -> None:
|
||||||
|
if element not in self:
|
||||||
|
self._list.insert(pos, element)
|
||||||
|
super().add(element)
|
||||||
|
|
||||||
|
def discard(self, element: _T) -> None: # type: ignore[override,unused-ignore] # noqa: E501
|
||||||
|
if element in self:
|
||||||
|
self._list.remove(element)
|
||||||
|
super().remove(element)
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
super().clear()
|
||||||
|
self._list = []
|
||||||
|
|
||||||
|
def __getitem__(self, key: int) -> _T:
|
||||||
|
return self._list[key]
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[_T]:
|
||||||
|
return iter(self._list)
|
||||||
|
|
||||||
|
def __add__(self, other: Iterator[_T]) -> OrderedSet[_T]:
|
||||||
|
return self.union(other)
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "%s(%r)" % (self.__class__.__name__, self._list)
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
def update(self, *iterables: Iterable[_T]) -> None:
|
||||||
|
for iterable in iterables:
|
||||||
|
for e in iterable:
|
||||||
|
if e not in self:
|
||||||
|
self._list.append(e)
|
||||||
|
super().add(e)
|
||||||
|
|
||||||
|
def __ior__(self, other: AbstractSet[_S]) -> OrderedSet[Union[_T, _S]]:
|
||||||
|
self.update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def union(self, *other: Iterable[_S]) -> OrderedSet[Union[_T, _S]]:
|
||||||
|
result: OrderedSet[Union[_T, _S]] = self.copy()
|
||||||
|
result.update(*other)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __or__(self, other: AbstractSet[_S]) -> OrderedSet[Union[_T, _S]]:
|
||||||
|
return self.union(other)
|
||||||
|
|
||||||
|
def intersection(self, *other: Iterable[Any]) -> OrderedSet[_T]:
|
||||||
|
other_set: Set[Any] = set()
|
||||||
|
other_set.update(*other)
|
||||||
|
return self.__class__(a for a in self if a in other_set)
|
||||||
|
|
||||||
|
def __and__(self, other: AbstractSet[object]) -> OrderedSet[_T]:
|
||||||
|
return self.intersection(other)
|
||||||
|
|
||||||
|
def symmetric_difference(self, other: Iterable[_T]) -> OrderedSet[_T]: # type: ignore[override,unused-ignore] # noqa: E501
|
||||||
|
collection: Collection[_T]
|
||||||
|
if isinstance(other, set):
|
||||||
|
collection = other_set = other
|
||||||
|
elif isinstance(other, Collection):
|
||||||
|
collection = other
|
||||||
|
other_set = set(other)
|
||||||
|
else:
|
||||||
|
collection = list(other)
|
||||||
|
other_set = set(collection)
|
||||||
|
result = self.__class__(a for a in self if a not in other_set)
|
||||||
|
result.update(a for a in collection if a not in self)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __xor__(self, other: AbstractSet[_S]) -> OrderedSet[Union[_T, _S]]:
|
||||||
|
return cast(OrderedSet[Union[_T, _S]], self).symmetric_difference(
|
||||||
|
other
|
||||||
|
)
|
||||||
|
|
||||||
|
def difference(self, *other: Iterable[Any]) -> OrderedSet[_T]:
|
||||||
|
other_set = super().difference(*other)
|
||||||
|
return self.__class__(a for a in self._list if a in other_set)
|
||||||
|
|
||||||
|
def __sub__(self, other: AbstractSet[Optional[_T]]) -> OrderedSet[_T]: # type: ignore[override,unused-ignore] # noqa: E501
|
||||||
|
return self.difference(other)
|
||||||
|
|
||||||
|
def intersection_update(self, *other: Iterable[Any]) -> None:
|
||||||
|
super().intersection_update(*other)
|
||||||
|
self._list = [a for a in self._list if a in self]
|
||||||
|
|
||||||
|
def __iand__(self, other: AbstractSet[object]) -> OrderedSet[_T]:
|
||||||
|
self.intersection_update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def symmetric_difference_update(self, other: Iterable[Any]) -> None:
|
||||||
|
collection = other if isinstance(other, Collection) else list(other)
|
||||||
|
super().symmetric_difference_update(collection)
|
||||||
|
self._list = [a for a in self._list if a in self]
|
||||||
|
self._list += [a for a in collection if a in self]
|
||||||
|
|
||||||
|
def __ixor__(self, other: AbstractSet[_S]) -> OrderedSet[Union[_T, _S]]:
|
||||||
|
self.symmetric_difference_update(other)
|
||||||
|
return cast(OrderedSet[Union[_T, _S]], self)
|
||||||
|
|
||||||
|
def difference_update(self, *other: Iterable[Any]) -> None:
|
||||||
|
super().difference_update(*other)
|
||||||
|
self._list = [a for a in self._list if a in self]
|
||||||
|
|
||||||
|
def __isub__(self, other: AbstractSet[Optional[_T]]) -> OrderedSet[_T]: # type: ignore # noqa: E501
|
||||||
|
self.difference_update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class IdentitySet:
|
||||||
|
"""A set that considers only object id() for uniqueness.
|
||||||
|
|
||||||
|
This strategy has edge cases for builtin types- it's possible to have
|
||||||
|
two 'foo' strings in one of these sets, for example. Use sparingly.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
_members: Dict[int, Any]
|
||||||
|
|
||||||
|
def __init__(self, iterable: Optional[Iterable[Any]] = None):
|
||||||
|
self._members = dict()
|
||||||
|
if iterable:
|
||||||
|
self.update(iterable)
|
||||||
|
|
||||||
|
def add(self, value: Any) -> None:
|
||||||
|
self._members[id(value)] = value
|
||||||
|
|
||||||
|
def __contains__(self, value: Any) -> bool:
|
||||||
|
return id(value) in self._members
|
||||||
|
|
||||||
|
def remove(self, value: Any) -> None:
|
||||||
|
del self._members[id(value)]
|
||||||
|
|
||||||
|
def discard(self, value: Any) -> None:
|
||||||
|
try:
|
||||||
|
self.remove(value)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def pop(self) -> Any:
|
||||||
|
try:
|
||||||
|
pair = self._members.popitem()
|
||||||
|
return pair[1]
|
||||||
|
except KeyError:
|
||||||
|
raise KeyError("pop from an empty set")
|
||||||
|
|
||||||
|
def clear(self) -> None:
|
||||||
|
self._members.clear()
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
if isinstance(other, IdentitySet):
|
||||||
|
return self._members == other._members
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __ne__(self, other: Any) -> bool:
|
||||||
|
if isinstance(other, IdentitySet):
|
||||||
|
return self._members != other._members
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def issubset(self, iterable: Iterable[Any]) -> bool:
|
||||||
|
if isinstance(iterable, self.__class__):
|
||||||
|
other = iterable
|
||||||
|
else:
|
||||||
|
other = self.__class__(iterable)
|
||||||
|
|
||||||
|
if len(self) > len(other):
|
||||||
|
return False
|
||||||
|
for m in filterfalse(
|
||||||
|
other._members.__contains__, iter(self._members.keys())
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __le__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.issubset(other)
|
||||||
|
|
||||||
|
def __lt__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return len(self) < len(other) and self.issubset(other)
|
||||||
|
|
||||||
|
def issuperset(self, iterable: Iterable[Any]) -> bool:
|
||||||
|
if isinstance(iterable, self.__class__):
|
||||||
|
other = iterable
|
||||||
|
else:
|
||||||
|
other = self.__class__(iterable)
|
||||||
|
|
||||||
|
if len(self) < len(other):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for m in filterfalse(
|
||||||
|
self._members.__contains__, iter(other._members.keys())
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __ge__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.issuperset(other)
|
||||||
|
|
||||||
|
def __gt__(self, other: Any) -> bool:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return len(self) > len(other) and self.issuperset(other)
|
||||||
|
|
||||||
|
def union(self, iterable: Iterable[Any]) -> IdentitySet:
|
||||||
|
result = self.__class__()
|
||||||
|
members = self._members
|
||||||
|
result._members.update(members)
|
||||||
|
result._members.update((id(obj), obj) for obj in iterable)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __or__(self, other: Any) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.union(other)
|
||||||
|
|
||||||
|
def update(self, iterable: Iterable[Any]) -> None:
|
||||||
|
self._members.update((id(obj), obj) for obj in iterable)
|
||||||
|
|
||||||
|
def __ior__(self, other: Any) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
self.update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def difference(self, iterable: Iterable[Any]) -> IdentitySet:
|
||||||
|
result = self.__new__(self.__class__)
|
||||||
|
other: Collection[Any]
|
||||||
|
|
||||||
|
if isinstance(iterable, self.__class__):
|
||||||
|
other = iterable._members
|
||||||
|
else:
|
||||||
|
other = {id(obj) for obj in iterable}
|
||||||
|
result._members = {
|
||||||
|
k: v for k, v in self._members.items() if k not in other
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __sub__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.difference(other)
|
||||||
|
|
||||||
|
def difference_update(self, iterable: Iterable[Any]) -> None:
|
||||||
|
self._members = self.difference(iterable)._members
|
||||||
|
|
||||||
|
def __isub__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
self.difference_update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def intersection(self, iterable: Iterable[Any]) -> IdentitySet:
|
||||||
|
result = self.__new__(self.__class__)
|
||||||
|
|
||||||
|
other: Collection[Any]
|
||||||
|
|
||||||
|
if isinstance(iterable, self.__class__):
|
||||||
|
other = iterable._members
|
||||||
|
else:
|
||||||
|
other = {id(obj) for obj in iterable}
|
||||||
|
result._members = {
|
||||||
|
k: v for k, v in self._members.items() if k in other
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __and__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.intersection(other)
|
||||||
|
|
||||||
|
def intersection_update(self, iterable: Iterable[Any]) -> None:
|
||||||
|
self._members = self.intersection(iterable)._members
|
||||||
|
|
||||||
|
def __iand__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
self.intersection_update(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def symmetric_difference(self, iterable: Iterable[Any]) -> IdentitySet:
|
||||||
|
result = self.__new__(self.__class__)
|
||||||
|
if isinstance(iterable, self.__class__):
|
||||||
|
other = iterable._members
|
||||||
|
else:
|
||||||
|
other = {id(obj): obj for obj in iterable}
|
||||||
|
result._members = {
|
||||||
|
k: v for k, v in self._members.items() if k not in other
|
||||||
|
}
|
||||||
|
result._members.update(
|
||||||
|
(k, v) for k, v in other.items() if k not in self._members
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __xor__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
return self.symmetric_difference(other)
|
||||||
|
|
||||||
|
def symmetric_difference_update(self, iterable: Iterable[Any]) -> None:
|
||||||
|
self._members = self.symmetric_difference(iterable)._members
|
||||||
|
|
||||||
|
def __ixor__(self, other: IdentitySet) -> IdentitySet:
|
||||||
|
if not isinstance(other, IdentitySet):
|
||||||
|
return NotImplemented
|
||||||
|
self.symmetric_difference(other)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def copy(self) -> IdentitySet:
|
||||||
|
result = self.__new__(self.__class__)
|
||||||
|
result._members = self._members.copy()
|
||||||
|
return result
|
||||||
|
|
||||||
|
__copy__ = copy
|
||||||
|
|
||||||
|
def __len__(self) -> int:
|
||||||
|
return len(self._members)
|
||||||
|
|
||||||
|
def __iter__(self) -> Iterator[Any]:
|
||||||
|
return iter(self._members.values())
|
||||||
|
|
||||||
|
def __hash__(self) -> NoReturn:
|
||||||
|
raise TypeError("set objects are unhashable")
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "%s(%r)" % (type(self).__name__, list(self._members.values()))
|
||||||
|
|
||||||
|
|
||||||
|
def unique_list(
|
||||||
|
seq: Iterable[_T], hashfunc: Optional[Callable[[_T], int]] = None
|
||||||
|
) -> List[_T]:
|
||||||
|
seen: Set[Any] = set()
|
||||||
|
seen_add = seen.add
|
||||||
|
if not hashfunc:
|
||||||
|
return [x for x in seq if x not in seen and not seen_add(x)]
|
||||||
|
else:
|
||||||
|
return [
|
||||||
|
x
|
||||||
|
for x in seq
|
||||||
|
if hashfunc(x) not in seen and not seen_add(hashfunc(x))
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user